• Pipeline overview
  • Dataset generation
  • Data exploration and visualization
  • Robust feature evaluation
    • Feature importances: Random Forest
      • Mean decrease in impurity (MDI)
      • Permutation importance
      • MDI vs Permutation importance
    • Feature importances: LASSO
      • Coefficient-based variable importance
      • Permutation importance
      • Coefficient vs. Permutation importance
  • Generation of final model
    • Performance
    • Features: permutation importance
    • Comparison with bootstrap results
    • Features: permutation importance
    • Comparison with bootstrap results
  • Other cleanup

Project run parameters

no_tasks=2
seed = 9384
outcome = 'hv_drink'
fbase = '/scratch/p_gaydosh_lab/DSI/'
results_directory <- str_c(fbase, outcome, '/results_full_h2o_2')
set.seed(seed)

Purpose. In this work, we will explore the relation between identified measures of despair of interest (e.g., personality measures of self-consciousness, individual and composite item scores from the CES-D assessment) and descriptors of diseases of despair. We will achieve this goal through modeling the outcomes based on the included predictors, and robustly assess the importance of the included features in predicting the outcomes via bootstrapping. We will use two well-known machine learning models, random forests and LASSO, which are both frequently used to measure the relative importance of the predictors included in the models. Lastly, we’ll generate trained and tuned models using this reduced feature set which can be used by others wish to predict the identified outcomes.

Subject inclusion. For this investigation, we will omit the entirety of Wave 2. This is commonly done in analyses of AddHealth data due the design of the original study. Otherwise, our dataset will include only subjects who have predictor and outcome data in all of the waves.

Outcome variables. In this experiment, we assess suicidal ideation at Wave 5.

Predictor variables. The predictors for these models are hand-picked, and based on previous work, relevance, and subject matter expertise. The set of predictors and the set of outcomes are disjoint. Predictors from Waves 1-4 (excluding Wave 2, see above) are included, and will be detailed in the following analysis.

Pipeline overview

Dataset generation

The predictors we will be using will be the the variable predictor_list loaded from 10-import-data.Rmd file. These initial set of predictors will be based of the list of variables that describe anxiety, depression, and optimism.

## set outcome variable of interest
filebase = '/scratch/p_gaydosh_lab'

#create data in specified form
dataset_list <- generate_datasets(outcome, binarize=FALSE, filebase=filebase, seed_val=seed)
Parsed with column specification:
cols(
  variable = col_character(),
  wave = col_double(),
  na_level = col_double(),
  type = col_character()
)
UNRELIABLE VALUE: Future (‘<none>’) unexpectedly generated random numbers without specifying argument '[future.]seed'. There is a risk that those random numbers are not statistically sound and the overall results might be invalid. To fix this, specify argument '[future.]seed', e.g. 'seed=TRUE'. This ensures that proper, parallel-safe random numbers are produced via the L'Ecuyer-CMRG method. To disable this check, use [future].seed=NULL, or set option 'future.rng.onMisuse' to "ignore".
UNRELIABLE VALUE: Future (‘<none>’) unexpectedly generated random numbers without specifying argument '[future.]seed'. There is a risk that those random numbers are not statistically sound and the overall results might be invalid. To fix this, specify argument '[future.]seed', e.g. 'seed=TRUE'. This ensures that proper, parallel-safe random numbers are produced via the L'Ecuyer-CMRG method. To disable this check, use [future].seed=NULL, or set option 'future.rng.onMisuse' to "ignore".
UNRELIABLE VALUE: Future (‘<none>’) unexpectedly generated random numbers without specifying argument '[future.]seed'. There is a risk that those random numbers are not statistically sound and the overall results might be invalid. To fix this, specify argument '[future.]seed', e.g. 'seed=TRUE'. This ensures that proper, parallel-safe random numbers are produced via the L'Ecuyer-CMRG method. To disable this check, use [future].seed=NULL, or set option 'future.rng.onMisuse' to "ignore".
UNRELIABLE VALUE: Future (‘<none>’) unexpectedly generated random numbers without specifying argument '[future.]seed'. There is a risk that those random numbers are not statistically sound and the overall results might be invalid. To fix this, specify argument '[future.]seed', e.g. 'seed=TRUE'. This ensures that proper, parallel-safe random numbers are produced via the L'Ecuyer-CMRG method. To disable this check, use [future].seed=NULL, or set option 'future.rng.onMisuse' to "ignore".
UNRELIABLE VALUE: Future (‘<none>’) unexpectedly generated random numbers without specifying argument '[future.]seed'. There is a risk that those random numbers are not statistically sound and the overall results might be invalid. To fix this, specify argument '[future.]seed', e.g. 'seed=TRUE'. This ensures that proper, parallel-safe random numbers are produced via the L'Ecuyer-CMRG method. To disable this check, use [future].seed=NULL, or set option 'future.rng.onMisuse' to "ignore".0 subjects removed from dataset.
[1] "Recoding Missing Factor Variables"
[1] "Number of factor variables being recoded :  98"
[1] "Factor variables being recoded : "
 [1] "h1fs1"   "h1fs3"   "h1fs4"   "h1fs5"   "h1fs6"   "h1fs7"   "h1fs11"  "h1fs15"  "h1fs16"  "h1fs17" 
[11] "h1fs19"  "h1ee14"  "h1ee12"  "h1ds14"  "h1ed9"   "h1ed7"   "h1ds3"   "h1fv7"   "h1fv1"   "h1fv8"  
[21] "h1jo9"   "h1ds13"  "h1ds12"  "h1ds11"  "h3sp5"   "h3sp6"   "h3sp7"   "h3sp8"   "h3sp9"   "h3sp10" 
[31] "h3sp11"  "h3sp12"  "h3sp13"  "h3ec56"  "h3ds18h" "h3ds18a" "h3ds18i" "h3to49"  "h3ds6"   "h3ds5"  
[41] "h3ds4"   "h4id5h"  "h4mh18"  "h4mh19"  "h4mh20"  "h4mh21"  "h4mh22"  "h4mh23"  "h4mh24"  "h4mh25" 
[51] "h4mh26"  "h4mh27"  "h4id5j"  "h4pe6"   "h4pe14"  "h4pe22"  "h4pe30"  "h4pe7"   "h4pe15"  "h4pe23" 
[61] "h4pe31"  "h4mh3"   "h4mh4"   "h4mh5"   "h4mh6"   "h4mh2"   "hdl"     "ldl"     "tg"      "h4bpcls"
[71] "h4ds7"   "h4ds19"  "h4ds14"  "h4ds20"  "h4ds6"   "h4ds5"   "h4ds4"   "h4cj17"  "h5id6g"  "h5ss0a" 
[81] "h5ss0b"  "h5ss0c"  "h5ss0d"  "h5ss0e"  "h5id6i"  "h5pe1"   "h5pe2"   "h5pe3"   "h5mn1"   "h5mn2"  
[91] "h5mn3"   "h5mn4"   "h5cj1d"  "h5cj1e"  "h5cj1f"  "h5cj1b"  "h5cj1c"  "h5cj1a" 
[1] "h1fs1"
[1] "h1fs3"
[1] "h1fs4"
[1] "h1fs5"
[1] "h1fs6"
[1] "h1fs7"
[1] "h1fs11"
[1] "h1fs15"
[1] "h1fs16"
[1] "h1fs17"
[1] "h1fs19"
[1] "h1ee14"
[1] "h1ee12"
[1] "h1ds14"
[1] "h1ed9"
[1] "h1ed7"
[1] "h1ds3"
[1] "h1fv7"
[1] "h1fv1"
[1] "h1fv8"
[1] "h1jo9"
[1] "h1ds13"
[1] "h1ds12"
[1] "h1ds11"
[1] "h3sp5"
[1] "h3sp6"
[1] "h3sp7"
[1] "h3sp8"
[1] "h3sp9"
[1] "h3sp10"
[1] "h3sp11"
[1] "h3sp12"
[1] "h3sp13"
[1] "h3ec56"
[1] "h3ds18h"
[1] "h3ds18a"
[1] "h3ds18i"
[1] "h3to49"
[1] "h3ds6"
[1] "h3ds5"
[1] "h3ds4"
[1] "h4id5h"
[1] "h4mh18"
[1] "h4mh19"
[1] "h4mh20"
[1] "h4mh21"
[1] "h4mh22"
[1] "h4mh23"
[1] "h4mh24"
[1] "h4mh25"
[1] "h4mh26"
[1] "h4mh27"
[1] "h4id5j"
[1] "h4pe6"
[1] "h4pe14"
[1] "h4pe22"
[1] "h4pe30"
[1] "h4pe7"
[1] "h4pe15"
[1] "h4pe23"
[1] "h4pe31"
[1] "h4mh3"
[1] "h4mh4"
[1] "h4mh5"
[1] "h4mh6"
[1] "h4mh2"
[1] "hdl"
[1] "ldl"
[1] "tg"
[1] "h4bpcls"
[1] "h4ds7"
[1] "h4ds19"
[1] "h4ds14"
[1] "h4ds20"
[1] "h4ds6"
[1] "h4ds5"
[1] "h4ds4"
[1] "h4cj17"
[1] "h5id6g"
[1] "h5ss0a"
[1] "h5ss0b"
[1] "h5ss0c"
[1] "h5ss0d"
[1] "h5ss0e"
[1] "h5id6i"
[1] "h5pe1"
[1] "h5pe2"
[1] "h5pe3"
[1] "h5mn1"
[1] "h5mn2"
[1] "h5mn3"
[1] "h5mn4"
[1] "h5cj1d"
[1] "h5cj1e"
[1] "h5cj1f"
[1] "h5cj1b"
[1] "h5cj1c"
[1] "h5cj1a"
   h1fs1    h1fs3    h1fs4    h1fs5    h1fs6    h1fs7   h1fs11   h1fs15   h1fs16   h1fs17   h1fs19   h1ee14 
"factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" 
  h1ee12   h1ds14    h1ed9    h1ed7    h1ds3    h1fv7    h1fv1    h1fv8    h1jo9   h1ds13   h1ds12   h1ds11 
"factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" 
   h3sp5    h3sp6    h3sp7    h3sp8    h3sp9   h3sp10   h3sp11   h3sp12   h3sp13   h3ec56  h3ds18h  h3ds18a 
"factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" 
 h3ds18i   h3to49    h3ds6    h3ds5    h3ds4   h4id5h   h4mh18   h4mh19   h4mh20   h4mh21   h4mh22   h4mh23 
"factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" 
  h4mh24   h4mh25   h4mh26   h4mh27   h4id5j    h4pe6   h4pe14   h4pe22   h4pe30    h4pe7   h4pe15   h4pe23 
"factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" 
  h4pe31    h4mh3    h4mh4    h4mh5    h4mh6    h4mh2      hdl      ldl       tg  h4bpcls    h4ds7   h4ds19 
"factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" 
  h4ds14   h4ds20    h4ds6    h4ds5    h4ds4   h4cj17   h5id6g   h5ss0a   h5ss0b   h5ss0c   h5ss0d   h5ss0e 
"factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" 
  h5id6i    h5pe1    h5pe2    h5pe3    h5mn1    h5mn2    h5mn3    h5mn4   h5cj1d   h5cj1e   h5cj1f   h5cj1b 
"factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" "factor" 
  h5cj1c   h5cj1a 
"factor" "factor" 
[1] "Recoding Missing Numeric Variables"
[1] "Number of numeric variables being recoded :  7"
[1] "Numeric variables being recoded : "
[1] "h1ed2"   "h4bmi"   "hba1c"   "crp"     "h4waist" "h4sbp"   "h4dbp"  
#parse out dataset components
wave_data <- dataset_list$wave_data
full_dataset <- dataset_list$full_dataset
ds_raw <- dataset_list$ds_raw_outcome
ds <- dataset_list$ds_final

#ml splits of the data
training_df <- dataset_list$training_df
validation_df <- dataset_list$validation_df
testing_df <- dataset_list$testing_df

Outcome variable: Binarizing and recoding details

The following table details the values present in the outcome variable. As we can see, we need to convert the variable into a factor, and drop the NAs.

ds_raw %>% 
  group_by(.data[[outcome]]) %>% 
  summarise(total = n(), type = class(.data[[outcome]]))
ABCDEFGHIJ0123456789
hv_drink
<dbl>
total
<int>
type
<chr>
08300numeric
1960numeric
NA89numeric

ds %>% 
  group_by(.data[[outcome]]) %>% 
  summarise(total = n(), type = class(.data[[outcome]]))
ABCDEFGHIJ0123456789
hv_drink
<fctr>
total
<int>
type
<chr>
08300factor
1960factor

print(str_c('Total number of subjects in unprocessed outcome data: ', nrow(ds_raw)))
[1] "Total number of subjects in unprocessed outcome data: 9349"
print(str_c('Total number of subjects in processed outcome data: ', nrow(ds)))
[1] "Total number of subjects in processed outcome data: 9260"
print(str_c('Total subjects dropped due to NA or skip: ', nrow(ds_raw)-nrow(ds)))
[1] "Total subjects dropped due to NA or skip: 89"

The table also demonstrates that the classes are very imbalanced, with about 14x the negative class as compared with the positive class. This is displayed graphically for easy consumption below.

ds_raw %>%
  explore_outcome(ds, outcome)
The original raw outcome data is displayed by converting it to a factor.  For more information about its actual type, investigate the ds_raw dataframe.  It is most likely a double.

After dropping the NAs, we see that we now have 9168 rows, which is consistent with the table above. The distribution of the data has a distinct imbalance as noted above. I think this warrants using pr_auc as the optimization and selection metric.

Data exploration and visualization

Here, we comment about the general characteristics of the data based on the provided visualizations. We comment on missingness of data, any strange or unusual behavior (e.g., strong imbalances), and any correlation that sticks out.

#Report about the characteristics of the subjects left out of the join
ds %>% explore_dropped()

# Visualize distributions of variables of interest
ds %>% 
  dplyr::select(-aid) %>%
  graph_bar_discrete(df = .,
                     plot_title = "Distributions of Discrete Variables",
                     max_categories = 50,
                     num_rows = 3,
                     num_cols = 3,
                     x_axis_size = 12,
                     y_axis_size = 12,
                     title_size = 15)

ds %>%
  graph_missing(only_missing = TRUE,
                title = "Percent Missing",
                box_line_size = .5,
                label_size = .5,
                x_axis_size = 12,
                y_axis_size = 12,
                title_size = 15)

ds %>%
  #dplyr::select(1:20) %>%
  pairwise_cramers_v() %>%
  plot_cramer_v(x_axis_angle = 90,
                plot_title = "Association among Categorical Variables",
                interactive = TRUE)
h4id5hh5id6gh1fs1h1fs3h1fs4h1fs5h1fs6h1fs7h1fs11h1fs15h1fs16h1fs17h1fs19h3sp5h3sp6h3sp7h3sp8h3sp9h3sp10h3sp11h3sp12h3sp13h4mh18h4mh19h4mh20h4mh21h4mh22h4mh23h4mh24h4mh25h4mh26h4mh27h5ss0ah5ss0bh5ss0ch5ss0dh5ss0eh5id6ih4id5jh4pe6h4pe14h4pe22h4pe30h4pe7h4pe15h4pe23h4pe31h5pe1h5pe2h5pe3h4mh3h4mh4h4mh5h4mh6h4mh2h5mn1h5mn2h5mn3h5mn4h1ee14h1ee12h3ec56hdlldltgh4bpclsh1ds14h1ed9h1ed7h1ds3h1fv7h1fv1h1fv8h1jo9h1ds13h1ds12h1ds11h3ds18hh3ds18ah3ds18ih3to49h3ds6h3ds5h3ds4h4ds7h4ds19h4ds14h4ds20h4ds6h4ds5h4ds4h4cj17h5cj1dh5cj1eh5cj1fh5cj1bh5cj1ch5cj1ahv_drinkh4id5hh5id6gh1fs1h1fs3h1fs4h1fs5h1fs6h1fs7h1fs11h1fs15h1fs16h1fs17h1fs19h3sp5h3sp6h3sp7h3sp8h3sp9h3sp10h3sp11h3sp12h3sp13h4mh18h4mh19h4mh20h4mh21h4mh22h4mh23h4mh24h4mh25h4mh26h4mh27h5ss0ah5ss0bh5ss0ch5ss0dh5ss0eh5id6ih4id5jh4pe6h4pe14h4pe22h4pe30h4pe7h4pe15h4pe23h4pe31h5pe1h5pe2h5pe3h4mh3h4mh4h4mh5h4mh6h4mh2h5mn1h5mn2h5mn3h5mn4h1ee14h1ee12h3ec56hdlldltgh4bpclsh1ds14h1ed9h1ed7h1ds3h1fv7h1fv1h1fv8h1jo9h1ds13h1ds12h1ds11h3ds18hh3ds18ah3ds18ih3to49h3ds6h3ds5h3ds4h4ds7h4ds19h4ds14h4ds20h4ds6h4ds5h4ds4h4cj17h5cj1dh5cj1eh5cj1fh5cj1bh5cj1c
Association among Categorical Variables

The correlation plot suggests that there are several variables we might think about removing. Firstly, there are moderate correlations among the individual predictor blocks; this is due to the way that they are ordered, since they’re essentially grouped into subsets. Addtionally, some predictor pairs have extremely high correlations, like (h4id5j, h4mh26) (correlation of 0.72), and many variables in the h4mh* series. (h3id5j, h4id5h) also has high correlation > 0.5. We may want to consider removing several of these in addition to the age variables because it may cause feature importance masking within our approaches.

Robust feature evaluation

The following table displays the mean performance metrics for the bootstrapped models on the validation set, removing values for which there are NA.


mean_bs_rf_perf <- bs_rf_perf %>%
  summarise_if(is.numeric, mean, na.rm=TRUE) %>%
  mutate(model = 'bs_rf') %>%
  dplyr::select(model, everything())

mean_bs_rf_perf
ABCDEFGHIJ0123456789
model
<chr>
accuracy
<dbl>
mpce
<dbl>
sens
<dbl>
spec
<dbl>
ppv
<dbl>
npv
<dbl>
roc_auc
<dbl>
pr_auc
<dbl>
tns
<dbl>
bs_rf0.89271060.49460250.016770830.99402410.24053780.89735980.64494370.17037561650.08

As shown, the bootstrapped models tend to have high specificity but low sensitivity, indicating that there is a challenge in identifying subjects with suicidal ideation.

Feature importances: Random Forest

Mean decrease in impurity (MDI)

boot_rf_mdi <- list(bs_rf_mdi) %>%
  get_median_placement(use_base_var = TRUE) %>%
  add_attribute_names('predictor', full_dataset) %>%
  dplyr::select(predictor, att_name, overall_rank)

head(boot_rf_mdi, 20)
ABCDEFGHIJ0123456789
predictor
<chr>
att_name
<chr>
overall_rank
<int>
h4dbpS27 DIASTOLIC BLOOD PRESSURE -W41
h4sbpS27 SYSTOLIC BLOOD PRESSURE-W42
age_w5age_w53
h4waistS27 MEASURED WAIST (CM) -W44
h4bmiS27 BMI -W45
hba1chba1c6
h3bmih3bmi7
crpcrp8
one_race5one_race59
h4cj17S22Q17 EVER INCARCERATED-W410

This table returns the MDI variable importance ranks that returned from each of the bootstrapped models.

# Needs to be fixed so that axes don't overlap each other and obscure understanding
plot_placement_boxplot(list(bs_rf_mdi))

Permutation importance

Now, let’s look at the permutation importance:

met <- 'pr_auc'
bs_rf_perm <- bs_rf_perm_plt %>%
  get_permute_placement(metric_oi=met) %>%
  add_attribute_names('predictor', full_dataset) %>%
  dplyr::select(predictor, everything())

head(bs_rf_perm, 20)
ABCDEFGHIJ0123456789
predictor
<chr>
att_name
<chr>
overall_rank
<int>
pr_auc
<dbl>
h3to49S28Q49 SINCE JUN95 HAVE DRIVEN DRUNK-W310.032480499
h4cj17S22Q17 EVER INCARCERATED-W420.025776504
h1jo9S30Q9 DRIVE WHILE DRUNK-W130.008134219
h1ds3S29Q3 LIE TO PARENTS ABOUT WHEREABOUT-W140.006922988
h4sbpS27 SYSTOLIC BLOOD PRESSURE-W450.005573834
h5ss0bS10Q0B PAST 7 DAY DEPRESSED-W560.005300182
one_race5one_race570.005147428
h4bmiS27 BMI -W480.004944561
h3ds5S26Q5 12 MO,OFT SELL DRUGS-W390.004825212
h1ds13S29Q13 STEAL WORTH < $50-W1100.004616366

MDI vs Permutation importance

In this step, we assess the differences generated between the different types of importances.

cbind(boot_rf_mdi[1:20,], dplyr::select(bs_rf_perm[1:20,], -all_of(met)))
ABCDEFGHIJ0123456789
predictor
<chr>
att_name
<chr>
overall_rank
<int>
predictor
<chr>
h4dbpS27 DIASTOLIC BLOOD PRESSURE -W41h3to49
h4sbpS27 SYSTOLIC BLOOD PRESSURE-W42h4cj17
age_w5age_w53h1jo9
h4waistS27 MEASURED WAIST (CM) -W44h1ds3
h4bmiS27 BMI -W45h4sbp
hba1chba1c6h5ss0b
h3bmih3bmi7one_race5
crpcrp8h4bmi
one_race5one_race59h3ds5
h4cj17S22Q17 EVER INCARCERATED-W410h1ds13

As shown, the MDI importance suffers from imbalances due to the number of values associated with a predictor. Because the wave ages have so many more values than the other factors, this artificially inflates their importance in MDI. The permutation importance is more intuitive.

plot_permute_var_imp(bs_rf_perm, metric = met)

In this step, we model the relation between the outcomes and the predictors using a linear regression with L2 regularization. This drives the importance of unimportant and redudant features towards zero.

mean_bs_lasso_perf <- bs_lasso_perf %>%
  summarise_if(is.numeric, mean, na.rm=TRUE) %>% 
  mutate(model='bs_lasso') %>%
  dplyr::select(model, everything())

mean_bs_lasso_perf
ABCDEFGHIJ0123456789
model
<chr>
accuracy
<dbl>
mpce
<dbl>
sens
<dbl>
spec
<dbl>
ppv
<dbl>
npv
<dbl>
roc_auc
<dbl>
pr_auc
<dbl>
tns
<dbl>
bs_lasso0.89632830.501NaN0.89632830.50.55183591660

Feature importances: LASSO

Coefficient-based variable importance

boot_lasso_mdi <- list(bs_lasso_mdi) %>%
  get_median_placement(use_base_var = TRUE) %>%
  add_attribute_names('predictor', full_dataset) %>%
  dplyr::select(predictor, att_name, overall_rank)

head(boot_lasso_mdi, 20)
ABCDEFGHIJ0123456789
predictor
<chr>
att_name
<chr>
overall_rank
<int>
hdlhdl1
ldlldl2
tgtg3
h3ec56S15Q56 CHANCE OF-LIVING TILL AGE 35-W34
h4pe7S26Q7 ALWAYS OPTIMISTIC ABOUT FUTURE-W45
h4pe15S26Q15 DO NOT EXPECT THINGS MY WAY-W46
h4pe23S26Q23 EXPECT MORE GOOD THAN BAD-W47
h4pe31S26Q31 RARELY EXPECT GOOD HAPPN TO ME-W48
h5pe1S9Q1 ALWAYS OPTIM ABOUT FUT-W59
h5pe2S9Q2 NOT EXPECT THINGS MY WAY-W510
plot_placement_boxplot(list(bs_lasso_mdi))

Permutation importance

bs_lasso_perm <- bs_lasso_perm_plt %>%
  get_permute_placement(metric_oi=met) %>% #set in random forest section
  add_attribute_names('predictor', full_dataset) %>%
  dplyr::select(predictor, everything())

head(bs_lasso_perm, 20)
ABCDEFGHIJ0123456789
predictor
<chr>
att_name
<chr>
overall_rank
<int>
pr_auc
<dbl>
age_w5age_w510
bio_sexBIOLOGICAL SEX-W120
crpcrp30
h1ds11S29Q11 USE OR THREATEN WITH A WEAPON-W140
h1ds12S29Q12 SELL DRUGS-W150
h1ds13S29Q13 STEAL WORTH < $50-W160
h1ds14S29Q14 TAKE PART IN A GROUP FIGHT-W170
h1ds3S29Q3 LIE TO PARENTS ABOUT WHEREABOUT-W180
h1ed2S5Q2 FREQ-SKIPPED SCHOOL-W190
h1ed7S5Q7 RECEIVED OUT-OF-SCHL SUSPENSION-W1100
plot_permute_var_imp(bs_lasso_perm, metric = met)

Coefficient vs. Permutation importance

Now, we compare the feature importances generated by the two different approaches. The traditional method of evaluating feature importance for regression methods is through analysis of the coefficients.

cbind(boot_lasso_mdi[1:20,], dplyr::select(bs_lasso_perm[1:20,], -met))
ABCDEFGHIJ0123456789
predictor
<chr>
att_name
<chr>
overall_rank
<int>
predictor
<chr>
hdlhdl1age_w5
ldlldl2bio_sex
tgtg3crp
h3ec56S15Q56 CHANCE OF-LIVING TILL AGE 35-W34h1ds11
h4pe7S26Q7 ALWAYS OPTIMISTIC ABOUT FUTURE-W45h1ds12
h4pe15S26Q15 DO NOT EXPECT THINGS MY WAY-W46h1ds13
h4pe23S26Q23 EXPECT MORE GOOD THAN BAD-W47h1ds14
h4pe31S26Q31 RARELY EXPECT GOOD HAPPN TO ME-W48h1ds3
h5pe1S9Q1 ALWAYS OPTIM ABOUT FUT-W59h1ed2
h5pe2S9Q2 NOT EXPECT THINGS MY WAY-W510h1ed7

The following table compares the mean performance of bootstrapped random forests to the mean performance of bootstrapped LASSO methods.

bs_comp_perfs <- bind_rows(mean_bs_rf_perf, mean_bs_lasso_perf) 
bs_comp_perfs
ABCDEFGHIJ0123456789
model
<chr>
accuracy
<dbl>
mpce
<dbl>
sens
<dbl>
spec
<dbl>
bs_rf0.89271060.49460250.016770830.9940241
bs_lasso0.89632830.50000000.000000001.0000000

Here, we look at the aggregated results of the bootstrapped predictors and compare the models generated to each other.

joined_results <- bs_rf_perm %>%
  dplyr::select(-met) %>%
  full_join(dplyr::select(bs_lasso_perm, -met), by=c("predictor", "att_name"), suffix=c('.rf', '.lasso')) %>%
  mutate(mean_rank = (overall_rank.rf+overall_rank.lasso)/2) %>%
  arrange(mean_rank)

head(joined_results, 20)
ABCDEFGHIJ0123456789
predictor
<chr>
att_name
<chr>
overall_rank.rf
<int>
overall_rank.lasso
<int>
mean_rank
<dbl>
h1ds3S29Q3 LIE TO PARENTS ABOUT WHEREABOUT-W1486.0
h1ds13S29Q13 STEAL WORTH < $50-W11068.0
age_w5age_w51618.5
bio_sexBIOLOGICAL SEX-W120211.0
h1ed7S5Q7 RECEIVED OUT-OF-SCHL SUSPENSION-W1141012.0
crpcrp21312.0
h1jo9S30Q9 DRIVE WHILE DRUNK-W132815.5
h3bmih3bmi122920.5
h3ds5S26Q5 12 MO,OFT SELL DRUGS-W393421.5
h3to49S28Q49 SINCE JUN95 HAVE DRIVEN DRUNK-W314623.5

The following visualization provides the intuition about the differences in the rankings between model types. They’re ordered by the overall mean importance, and for a given variable, the differences in rank are shown.

# Comparison of top_n features
joined_results %>%
  compare_feature_select(interactive = TRUE,
                         top_n = 100,
                         opacity = 0.50,
                         plot_title = "Permutation Importance of Predictors by Model")
0306090S10Q0D PAST 7 DAY SAD-W5S5Q6I EVER BEEN DX PANIC/ANXIETY DIS-W5S10Q0A PAST 7 DAY SHAKE BLUE-W5S21Q7 12 MO,OFT PART PHYS FIGHT/GRP-W4S10Q0C PAST 7 DAY HAPPY-W5S14Q27 PAST 7 DAYS FELT DISLIKED-W4S06Q5H EVER BEEN DX WITH DEPRESSION-W4S06Q5J EVER BEEN DX PANIC/ANXIETY DIS-W4S26Q7 ALWAYS OPTIMISTIC ABOUT FUTURE-W4S21Q20 12 MO,SHOT/STABBED SOMEONE-W4tgS21Q19 12 MO,PULL KNIFE/GUN SOMEONE-W4S26Q18I 12 MO,SHOT/STABBED SOMEONE-W3S13Q3 LAST MO FELT THINGS GO YOUR WAY-W5S26Q18A 12 MO,SAW ONE SHOOT/STAB PERS-W3S14Q4 LST MNTH CONF HANDLE PERS PROB-W4S21Q5 12 MO,OFT SELL DRUGS-W4S21Q6 12 MO,OFT STEAL SOMETHING/<$50-W4S9Q2 NOT EXPECT THINGS MY WAY-W5S13Q4 LAST MO DIFFS OVERWHELM-W5S26Q4 12 MO,OFT WEAPON GET SOMETHING-W3S26Q23 EXPECT MORE GOOD THAN BAD-W4S13Q1 LAST MO NO CNTRL IMPORT THINGS-W5S14Q19 PAST 7 DAYS SHAKE OFF BLUES-W4S21Q14 12 MO,SAW ONE SHOOT/STAB PERS-W4ldlS14Q20 PAST 7 DAYS FELT AS GOOD OTHRS-W4S14Q25 PAST 7 DAYS ENJOYED LIFE-W4S9Q3 EXPECT MORE GOOD-W5S14Q18 PAST 7 DAYS BOTHERED BY THINGS-W4S31Q7 PULLED A KNIFE/GUN ON SOMEONE-W1S26Q18H 12 MO,PULL KNIKE/GUN SOMEONE-W3S31Q8 SHOT/STABBED SOMEONE-W1S26Q6 WORRY ABOUT THINGS-W4S12Q13 PAST 7 DAYS PEOPLE DISLIKED U-W3S26Q30 DO NOT WORRY ABOUT PAST-W4hdlS12Q1 PAST 7 DAYS SHAKE OFF BLUES-W3S12Q9 PAST 7 DAYS WERE DEPRESSED-W3hba1cS14Q22 PAST 7 DAYS FELT DEPRESSED-W4S14Q24 PAST 7 DAYS FELT HAPPY-W4S31Q1 SAW SHOOTING/STABBING OF PERSON-W1one_race5S10Q19 LIFE NOT WORTH LIVING-W1S26Q15 DO NOT EXPECT THINGS MY WAY-W4S9Q1 ALWAYS OPTIM ABOUT FUT-W5S14Q3 LST MNTH UNABLE CONTROL THINGS-W4S26Q31 RARELY EXPECT GOOD HAPPN TO ME-W4S14Q26 PAST 7 DAYS FELT SAD-W4S29Q11 USE OR THREATEN WITH A WEAPON-W1S13Q2 LAST MO CONFID HANDLE PERS PBMS-W5S15Q56 CHANCE OF-LIVING TILL AGE 35-W3S26Q14 NOT EASILY BOTHERED BY THINGS-W4S5Q9 EXPELLED FROM SCHOOL-W1S10Q0B PAST 7 DAY DEPRESSED-W5S26Q22 I GET STRESSED OUT EASILY-W4S27 MEASURED WAIST (CM) -W4S14Q5 LST MNTH THINGS GOING YOUR WAY-W4S12Q5 PAST 7 DAYS BOTHERED BY THINGS-W3S10Q3 HAD THE BLUES-W1S14Q6 LST MNTH DIFFICULTIES OVERWHELM-W4S29Q12 SELL DRUGS-W1S5Q2 FREQ-SKIPPED SCHOOL-W1S12Q10 PAST 7 DAYS TOO TIRED DO THNGS-W3S12Q8 PAST 7 DAYS TROUBLE CONCENTRTNG-W3S14Q2 HOW OFTEN FEEL ISOLATED-W4S10Q6 FELT DEPRESSED-W1S12Q11 PAST 7 DAYS ENJOYED LIFE-W3S10Q7 TOO TIRED TO DO THINGS-W1S10Q17 FELT PEOPLE DISLIKE YOU-W1S12Q7 PAST 7 DAYS FELT AS GOOD AS OTH-W3S14Q23 PAST 7 DAYS FELT TOO TIRED-W4S29Q14 TAKE PART IN A GROUP FIGHT-W1S27 SYSTOLIC BLOOD PRESSURE-W4S12Q12 PAST 7 DAYS WERE SAD-W3S14Q21 PAST 7 DAYS TROUBL CONCENTRTNG-W4S10Q16 FELT SAD-W1S38Q14 CHANCES-KILLED BY AGE 21-W1S27 BLOOD PRESSURE CLASS -W4S38Q12 CHANCES-LIVE TO AGE 35-W1S26Q6 12 MO,OFT STEAL SOMETHING/<$50-W3S10Q15 ENJOYED LIFE-W1S27 DIASTOLIC BLOOD PRESSURE -W4S10Q11 HAPPY-W1S10Q4 JUST AS GOOD AS OTHER PEOPLE-W1S27 BMI -W4S10Q5 TROUBLE KEEPING MIND FOCUSED-W1S22Q17 EVER INCARCERATED-W4S10Q1 BOTHERED BY THINGS-W1S28Q49 SINCE JUN95 HAVE DRIVEN DRUNK-W3S26Q5 12 MO,OFT SELL DRUGS-W3h3bmiS30Q9 DRIVE WHILE DRUNK-W1crpS5Q7 RECEIVED OUT-OF-SCHL SUSPENSION-W1BIOLOGICAL SEX-W1age_w5S29Q13 STEAL WORTH < $50-W1S29Q3 LIE TO PARENTS ABOUT WHEREABOUT-W1
overall_rank.lassooverall_rank.rfPermutation Importance of Predictors by ModelPlacementsPredictorsmodel

Generation of final model

In this step, we build the final model for the random forest. We use slightly more values in order to come up with the best model, keeping in mind the number of combinations that are required to run to evaluate the grid.


final_rf_perf = NULL
  
# read file array
final_rf_perfs = load_from_csv(final_rf_perf, results_directory, no_tasks)

# get the index of the best performance and best performance
final_rfmodel_ind <- which.max(dplyr::select(final_rf_perfs, met) %>% pull(met))
final_rf_perf <- final_rf_perfs %>% slice(final_rfmodel_ind)

# load the model of interest
final_model_rf <- load_best_model('final_rf_model', results_directory, final_rfmodel_ind)

Performance

The final random forest performance metrics are shown below:

# show model final performance
print(final_rf_perf)
ABCDEFGHIJ0123456789
accuracy
<dbl>
kap
<dbl>
sens
<dbl>
spec
<dbl>
ppv
<dbl>
npv
<dbl>
mcc
<dbl>
j_index
<dbl>
bal_accuracy
<dbl>
0.78401730.18898560.44791670.82289160.22631580.92798910.20441880.27080820.6354041

Features: permutation importance


final_rf_perm_plt = NULL
  
# read best perm plt
final_rf_perm_plt = load_from_csv(final_rf_perm_plt, results_directory, best_ind=final_rfmodel_ind)
final_rf_perm <- final_rf_perm_plt %>%
  get_permute_placement(metric_oi=met) %>%
  add_attribute_names('predictor', full_dataset) %>%
  dplyr::select(predictor, everything())

head(final_rf_perm, 20)
ABCDEFGHIJ0123456789
predictor
<chr>
att_name
<chr>
overall_rank
<int>
pr_auc
<dbl>
h3to49S28Q49 SINCE JUN95 HAVE DRIVEN DRUNK-W310.13082232
h4cj17S22Q17 EVER INCARCERATED-W420.08355264
h5ss0bS10Q0B PAST 7 DAY DEPRESSED-W530.05266288
h1jo9S30Q9 DRIVE WHILE DRUNK-W140.05145937
h1ds3S29Q3 LIE TO PARENTS ABOUT WHEREABOUT-W150.03660994
h1ed7S5Q7 RECEIVED OUT-OF-SCHL SUSPENSION-W160.03305730
h3bmih3bmi70.02856768
h1ds13S29Q13 STEAL WORTH < $50-W180.02772813
age_w5age_w590.02662387
h4mh26S14Q26 PAST 7 DAYS FELT SAD-W4100.02569401
plot_permute_var_imp(final_rf_perm, metric = met)

Comparison with bootstrap results

This section investigates the differences in the bootstrap results vs the features generated from the random forest final model. The following table shows the overall differences in rank.

rf_joined_results <- final_rf_perm %>%
  dplyr::select(-met) %>%
  full_join(dplyr::select(bs_rf_perm, -met), by=c("predictor", "att_name"), suffix=c('.final', '.bootstrap')) %>%
  mutate(mean_rank = (overall_rank.final + overall_rank.bootstrap)/2) %>%
  arrange(mean_rank)

head(rf_joined_results, 20)
ABCDEFGHIJ0123456789
predictor
<chr>
att_name
<chr>
overall_rank.final
<int>
overall_rank.bootstrap
<int>
h3to49S28Q49 SINCE JUN95 HAVE DRIVEN DRUNK-W311
h4cj17S22Q17 EVER INCARCERATED-W422
h1jo9S30Q9 DRIVE WHILE DRUNK-W143
h5ss0bS10Q0B PAST 7 DAY DEPRESSED-W536
h1ds3S29Q3 LIE TO PARENTS ABOUT WHEREABOUT-W154
h1ds13S29Q13 STEAL WORTH < $50-W1810
one_race5one_race5117
h3bmih3bmi712
h1ed7S5Q7 RECEIVED OUT-OF-SCHL SUSPENSION-W1614
age_w5age_w5916

The following plot provides visualizations for the difference in the final model rankings vs the bootstrap.

# Comparison of top_n features
rf_joined_results %>%
  compare_feature_select(sel_cols = c("overall_rank.final", "overall_rank.bootstrap"),
    interactive = TRUE,
    top_n = 100,
    opacity = 0.50,
    plot_title = "Permutation Importance of Predictors: Final vs. Bootstrap")
0306090S29Q11 USE OR THREATEN WITH A WEAPON-W1S31Q7 PULLED A KNIFE/GUN ON SOMEONE-W1S31Q8 SHOT/STABBED SOMEONE-W1S26Q18H 12 MO,PULL KNIKE/GUN SOMEONE-W3S21Q5 12 MO,OFT SELL DRUGS-W4S5Q9 EXPELLED FROM SCHOOL-W1S31Q1 SAW SHOOTING/STABBING OF PERSON-W1S29Q12 SELL DRUGS-W1S10Q19 LIFE NOT WORTH LIVING-W1S21Q6 12 MO,OFT STEAL SOMETHING/<$50-W4S5Q2 FREQ-SKIPPED SCHOOL-W1S14Q1A 12 MO DAMAGE PROP/NOT YOUR-W5S14Q1D 12 MO GET IN PHYS FIGHT-W5S12Q13 PAST 7 DAYS PEOPLE DISLIKED U-W3S29Q14 TAKE PART IN A GROUP FIGHT-W1S14Q27 PAST 7 DAYS FELT DISLIKED-W4S21Q20 12 MO,SHOT/STABBED SOMEONE-W4S06Q5J EVER BEEN DX PANIC/ANXIETY DIS-W4S21Q19 12 MO,PULL KNIFE/GUN SOMEONE-W4S5Q6G EVER BEEN DX WITH DEPRESSION-W5S10Q3 HAD THE BLUES-W1S14Q20 PAST 7 DAYS FELT AS GOOD OTHRS-W4S21Q14 12 MO,SAW ONE SHOOT/STAB PERS-W4S10Q6 FELT DEPRESSED-W1S10Q7 TOO TIRED TO DO THINGS-W1S38Q14 CHANCES-KILLED BY AGE 21-W1S10Q17 FELT PEOPLE DISLIKE YOU-W1S10Q0E PAST 7 DAY NOT WORTH-W5S12Q1 PAST 7 DAYS SHAKE OFF BLUES-W3S06Q5H EVER BEEN DX WITH DEPRESSION-W4S12Q9 PAST 7 DAYS WERE DEPRESSED-W3S26Q7 ALWAYS OPTIMISTIC ABOUT FUTURE-W4S10Q0A PAST 7 DAY SHAKE BLUE-W5S14Q25 PAST 7 DAYS ENJOYED LIFE-W4S38Q12 CHANCES-LIVE TO AGE 35-W1S12Q10 PAST 7 DAYS TOO TIRED DO THNGS-W3S15Q56 CHANCE OF-LIVING TILL AGE 35-W3S10Q16 FELT SAD-W1S5Q6I EVER BEEN DX PANIC/ANXIETY DIS-W5S26Q23 EXPECT MORE GOOD THAN BAD-W4S12Q11 PAST 7 DAYS ENJOYED LIFE-W3S14Q19 PAST 7 DAYS SHAKE OFF BLUES-W4S14Q24 PAST 7 DAYS FELT HAPPY-W4S14Q4 LST MNTH CONF HANDLE PERS PROB-W4S13Q3 LAST MO FELT THINGS GO YOUR WAY-W5S13Q1 LAST MO NO CNTRL IMPORT THINGS-W5S26Q31 RARELY EXPECT GOOD HAPPN TO ME-W4S10Q0C PAST 7 DAY HAPPY-W5S10Q4 JUST AS GOOD AS OTHER PEOPLE-W1S14Q3 LST MNTH UNABLE CONTROL THINGS-W4S12Q8 PAST 7 DAYS TROUBLE CONCENTRTNG-W3S14Q18 PAST 7 DAYS BOTHERED BY THINGS-W4S10Q15 ENJOYED LIFE-W1tgS12Q5 PAST 7 DAYS BOTHERED BY THINGS-W3S9Q2 NOT EXPECT THINGS MY WAY-W5S26Q22 I GET STRESSED OUT EASILY-W4S12Q7 PAST 7 DAYS FELT AS GOOD AS OTH-W3S13Q4 LAST MO DIFFS OVERWHELM-W5S10Q0D PAST 7 DAY SAD-W5S27 SYSTOLIC BLOOD PRESSURE-W4S14Q5 LST MNTH THINGS GOING YOUR WAY-W4ldlS26Q30 DO NOT WORRY ABOUT PAST-W4S27 MEASURED WAIST (CM) -W4S10Q5 TROUBLE KEEPING MIND FOCUSED-W1S12Q12 PAST 7 DAYS WERE SAD-W3S14Q2 HOW OFTEN FEEL ISOLATED-W4S14Q22 PAST 7 DAYS FELT DEPRESSED-W4S26Q6 WORRY ABOUT THINGS-W4S9Q3 EXPECT MORE GOOD-W5S10Q11 HAPPY-W1S26Q6 12 MO,OFT STEAL SOMETHING/<$50-W3S10Q1 BOTHERED BY THINGS-W1S26Q15 DO NOT EXPECT THINGS MY WAY-W4S14Q23 PAST 7 DAYS FELT TOO TIRED-W4S26Q14 NOT EASILY BOTHERED BY THINGS-W4S26Q5 12 MO,OFT SELL DRUGS-W3hdlS27 DIASTOLIC BLOOD PRESSURE -W4crpS27 BMI -W4S14Q26 PAST 7 DAYS FELT SAD-W4S27 BLOOD PRESSURE CLASS -W4S9Q1 ALWAYS OPTIM ABOUT FUT-W5S14Q6 LST MNTH DIFFICULTIES OVERWHELM-W4S14Q21 PAST 7 DAYS TROUBL CONCENTRTNG-W4BIOLOGICAL SEX-W1S13Q2 LAST MO CONFID HANDLE PERS PBMS-W5hba1cage_w5S5Q7 RECEIVED OUT-OF-SCHL SUSPENSION-W1h3bmione_race5S29Q13 STEAL WORTH < $50-W1S10Q0B PAST 7 DAY DEPRESSED-W5S29Q3 LIE TO PARENTS ABOUT WHEREABOUT-W1S30Q9 DRIVE WHILE DRUNK-W1S22Q17 EVER INCARCERATED-W4S28Q49 SINCE JUN95 HAVE DRIVEN DRUNK-W3
overall_rank.bootstrapoverall_rank.finalPermutation Importance of Predictors: Final vs. BootstrapPlacementsPredictorsmodel

Now, we create the final model for LASSO. There is no substantial difference between this method and the bootstrap methods, other than the data upon which the model is being built.


final_lasso_perf = NULL
  
# read file array
final_lasso_perfs = load_from_csv(final_lasso_perf, results_directory, no_tasks)

# get the index of the best performance and best performance
final_lassomodel_ind <- which.max(dplyr::select(final_lasso_perfs, met) %>% pull(met))
final_lasso_perf <- final_lasso_perfs %>% slice(final_lassomodel_ind)

# load the model of interest
final_model_lasso <- load_best_model('final_lasso_model', results_directory, final_lassomodel_ind)

The final LASSO performance metrics are shown below:

# show model final performance
print(final_lasso_perf)
ABCDEFGHIJ0123456789
accuracy
<dbl>
kap
<dbl>
sens
<dbl>
spec
<dbl>
ppv
<dbl>
0.79697620.18527120.406250.84216870.2294118

Features: permutation importance


final_lasso_perm_plt = NULL

#load best index permutation from file  
final_lasso_perm_plt = load_from_csv(final_lasso_perm_plt, results_directory, best_ind=final_lassomodel_ind)
final_lasso_perm <- final_lasso_perm_plt %>%
  get_permute_placement(metric_oi=met) %>%
  add_attribute_names('predictor', full_dataset) %>%
  dplyr::select(predictor, everything())

head(final_lasso_perm, 20)
ABCDEFGHIJ0123456789
predictor
<chr>
att_name
<chr>
overall_rank
<int>
pr_auc
<dbl>
h3to49S28Q49 SINCE JUN95 HAVE DRIVEN DRUNK-W310.061443999
h4sbpS27 SYSTOLIC BLOOD PRESSURE-W420.017168231
h5ss0bS10Q0B PAST 7 DAY DEPRESSED-W530.015379363
h4mh26S14Q26 PAST 7 DAYS FELT SAD-W440.009452195
one_race5one_race550.009447363
hdlhdl60.007377558
h4pe15S26Q15 DO NOT EXPECT THINGS MY WAY-W470.006213813
h4waistS27 MEASURED WAIST (CM) -W480.006087166
age_w5age_w590.005305896
h5pe2S9Q2 NOT EXPECT THINGS MY WAY-W5100.004757935
plot_permute_var_imp(final_lasso_perm, metric = met)

Comparison with bootstrap results

This section investigates the differences in the bootstrap results vs the features generated from the LASSO final model. The following table shows the overall differences in rank.

lasso_joined_results <- final_lasso_perm %>%
  dplyr::select(-met) %>%
  full_join(dplyr::select(bs_lasso_perm, -met), by=c("predictor", "att_name"), suffix=c('.final', '.bootstrap')) %>%
  mutate(mean_rank = (overall_rank.final + overall_rank.bootstrap)/2) %>%
  arrange(mean_rank)

head(lasso_joined_results, 20)
ABCDEFGHIJ0123456789
predictor
<chr>
att_name
<chr>
overall_rank.final
<int>
overall_rank.bootstrap
<int>
mean_rank
<dbl>
age_w5age_w5915.0
h1ds3S29Q3 LIE TO PARENTS ABOUT WHEREABOUT-W112810.0
h1ed7S5Q7 RECEIVED OUT-OF-SCHL SUSPENSION-W1161013.0
h1fs1S10Q1 BOTHERED BY THINGS-W1181416.0
crpcrp33318.0
h3to49S28Q49 SINCE JUN95 HAVE DRIVEN DRUNK-W314623.5
h1ds11S29Q11 USE OR THREATEN WITH A WEAPON-W145424.5
h1ds12S29Q12 SELL DRUGS-W146525.5
h1fs5S10Q5 TROUBLE KEEPING MIND FOCUSED-W1322227.0
h1ds14S29Q14 TAKE PART IN A GROUP FIGHT-W147727.0

The following plot provides visualizations for the difference in the final model rankings vs the bootstrap.

# Comparison of top_n features
lasso_joined_results %>%
  compare_feature_select(sel_cols = c("overall_rank.final", "overall_rank.bootstrap"),
    interactive = TRUE,
    top_n = 100,
    opacity = 0.50,
    plot_title = "Permutation Importance of Predictors: Final vs. Bootstrap")
0306090S14Q1D 12 MO GET IN PHYS FIGHT-W5S14Q1C 12 MO SELL DRUGS-W5S14Q1B 12 MO STEAL SOMETHING/>$50-W5S14Q1A 12 MO DAMAGE PROP/NOT YOUR-W5S14Q23 PAST 7 DAYS FELT TOO TIRED-W4S26Q6 WORRY ABOUT THINGS-W4S26Q30 DO NOT WORRY ABOUT PAST-W4S14Q19 PAST 7 DAYS SHAKE OFF BLUES-W4S26Q14 NOT EASILY BOTHERED BY THINGS-W4S14Q5 LST MNTH THINGS GOING YOUR WAY-W4S14Q4 LST MNTH CONF HANDLE PERS PROB-W4S14Q3 LST MNTH UNABLE CONTROL THINGS-W4S14Q27 PAST 7 DAYS FELT DISLIKED-W4S14Q25 PAST 7 DAYS ENJOYED LIFE-W4tgS14Q24 PAST 7 DAYS FELT HAPPY-W4S14Q20 PAST 7 DAYS FELT AS GOOD OTHRS-W4S13Q4 LAST MO DIFFS OVERWHELM-W5S26Q6 12 MO,OFT STEAL SOMETHING/<$50-W3S06Q5J EVER BEEN DX PANIC/ANXIETY DIS-W4S9Q3 EXPECT MORE GOOD-W5S06Q5H EVER BEEN DX WITH DEPRESSION-W4S21Q7 12 MO,OFT PART PHYS FIGHT/GRP-W4S21Q6 12 MO,OFT STEAL SOMETHING/<$50-W4S21Q5 12 MO,OFT SELL DRUGS-W4S13Q3 LAST MO FELT THINGS GO YOUR WAY-W5hba1cS21Q4 12 MO,OFT WEAPON GET SOMETHING-W4S21Q20 12 MO,SHOT/STABBED SOMEONE-W4S21Q19 12 MO,PULL KNIFE/GUN SOMEONE-W4S21Q14 12 MO,SAW ONE SHOOT/STAB PERS-W4S10Q11 HAPPY-W1S9Q1 ALWAYS OPTIM ABOUT FUT-W5S26Q22 I GET STRESSED OUT EASILY-W4S29Q13 STEAL WORTH < $50-W1S12Q8 PAST 7 DAYS TROUBLE CONCENTRTNG-W3S26Q23 EXPECT MORE GOOD THAN BAD-W4one_race5hdlS12Q7 PAST 7 DAYS FELT AS GOOD AS OTH-W3BIOLOGICAL SEX-W1S12Q5 PAST 7 DAYS BOTHERED BY THINGS-W3S9Q2 NOT EXPECT THINGS MY WAY-W5S12Q13 PAST 7 DAYS PEOPLE DISLIKED U-W3S13Q2 LAST MO CONFID HANDLE PERS PBMS-W5S10Q0B PAST 7 DAY DEPRESSED-W5S14Q2 HOW OFTEN FEEL ISOLATED-W4S14Q2B 12 MO SAW ONE SHOOT/STAB PERS-W5S15Q56 CHANCE OF-LIVING TILL AGE 35-W3S26Q4 12 MO,OFT WEAPON GET SOMETHING-W3S26Q18I 12 MO,SHOT/STABBED SOMEONE-W3S14Q6 LST MNTH DIFFICULTIES OVERWHELM-W4S26Q18H 12 MO,PULL KNIKE/GUN SOMEONE-W3S26Q31 RARELY EXPECT GOOD HAPPN TO ME-W4S26Q7 ALWAYS OPTIMISTIC ABOUT FUTURE-W4S26Q18A 12 MO,SAW ONE SHOOT/STAB PERS-W3S14Q22 PAST 7 DAYS FELT DEPRESSED-W4S27 MEASURED WAIST (CM) -W4h3bmiS30Q9 DRIVE WHILE DRUNK-W1S31Q8 SHOT/STABBED SOMEONE-W1S27 DIASTOLIC BLOOD PRESSURE -W4S27 SYSTOLIC BLOOD PRESSURE-W4S31Q7 PULLED A KNIFE/GUN ON SOMEONE-W1S14Q21 PAST 7 DAYS TROUBL CONCENTRTNG-W4S26Q15 DO NOT EXPECT THINGS MY WAY-W4S31Q1 SAW SHOOTING/STABBING OF PERSON-W1S14Q18 PAST 7 DAYS BOTHERED BY THINGS-W4S10Q7 TOO TIRED TO DO THINGS-W1S12Q11 PAST 7 DAYS ENJOYED LIFE-W3S10Q6 FELT DEPRESSED-W1S27 BLOOD PRESSURE CLASS -W4S27 BMI -W4S10Q4 JUST AS GOOD AS OTHER PEOPLE-W1S10Q19 LIFE NOT WORTH LIVING-W1S14Q26 PAST 7 DAYS FELT SAD-W4S12Q9 PAST 7 DAYS WERE DEPRESSED-W3S10Q16 FELT SAD-W1S12Q1 PAST 7 DAYS SHAKE OFF BLUES-W3S10Q15 ENJOYED LIFE-W1S22Q17 EVER INCARCERATED-W4S12Q10 PAST 7 DAYS TOO TIRED DO THNGS-W3S38Q14 CHANCES-KILLED BY AGE 21-W1S38Q12 CHANCES-LIVE TO AGE 35-W1S5Q9 EXPELLED FROM SCHOOL-W1S26Q5 12 MO,OFT SELL DRUGS-W3S10Q17 FELT PEOPLE DISLIKE YOU-W1S5Q2 FREQ-SKIPPED SCHOOL-W1S10Q3 HAD THE BLUES-W1S12Q12 PAST 7 DAYS WERE SAD-W3S10Q5 TROUBLE KEEPING MIND FOCUSED-W1S29Q14 TAKE PART IN A GROUP FIGHT-W1S29Q12 SELL DRUGS-W1S29Q11 USE OR THREATEN WITH A WEAPON-W1S28Q49 SINCE JUN95 HAVE DRIVEN DRUNK-W3crpS10Q1 BOTHERED BY THINGS-W1S5Q7 RECEIVED OUT-OF-SCHL SUSPENSION-W1S29Q3 LIE TO PARENTS ABOUT WHEREABOUT-W1age_w5
overall_rank.bootstrapoverall_rank.finalPermutation Importance of Predictors: Final vs. BootstrapPlacementsPredictorsmodel

Here, we compare the features generated by the permutation importance between the two final models.

rf_lasso_final_joined_results <- final_rf_perm %>%
  dplyr::select(-met) %>%
  full_join(dplyr::select(final_lasso_perm, -met), by=c("predictor", "att_name"), suffix=c('.rf', '.lasso')) %>%
  mutate(mean_rank = (overall_rank.rf+overall_rank.lasso)/2) %>%
  arrange(mean_rank)

head(rf_lasso_final_joined_results, 20)
ABCDEFGHIJ0123456789
predictor
<chr>
att_name
<chr>
overall_rank.rf
<int>
overall_rank.lasso
<int>
mean_rank
<dbl>
h3to49S28Q49 SINCE JUN95 HAVE DRIVEN DRUNK-W3111.0
h5ss0bS10Q0B PAST 7 DAY DEPRESSED-W5333.0
h4mh26S14Q26 PAST 7 DAYS FELT SAD-W41047.0
one_race5one_race51158.0
h1ds3S29Q3 LIE TO PARENTS ABOUT WHEREABOUT-W15128.5
age_w5age_w5999.0
h4cj17S22Q17 EVER INCARCERATED-W421910.5
h1ed7S5Q7 RECEIVED OUT-OF-SCHL SUSPENSION-W161611.0
h5mn2S13Q2 LAST MO CONFID HANDLE PERS PBMS-W5141112.5
h4pe15S26Q15 DO NOT EXPECT THINGS MY WAY-W419713.0

The following visualization provides the intuition about the differences in the rankings between the final model types. They’re ordered by the overall mean importance, and for a given variable, the differences in rank are shown.

# Comparison of top_n features
rf_lasso_final_joined_results %>%
  compare_feature_select(sel_cols = c("overall_rank.rf", "overall_rank.lasso"),
    interactive = TRUE,
    top_n = 100,
    opacity = 0.50,
    plot_title = "Permutation Importance of Predictors: Random Forest vs Lasso")
0306090S14Q1A 12 MO DAMAGE PROP/NOT YOUR-W5S14Q1D 12 MO GET IN PHYS FIGHT-W5S14Q27 PAST 7 DAYS FELT DISLIKED-W4S26Q18A 12 MO,SAW ONE SHOOT/STAB PERS-W3S10Q0E PAST 7 DAY NOT WORTH-W5S14Q20 PAST 7 DAYS FELT AS GOOD OTHRS-W4S26Q4 12 MO,OFT WEAPON GET SOMETHING-W3S26Q18I 12 MO,SHOT/STABBED SOMEONE-W3S13Q1 LAST MO NO CNTRL IMPORT THINGS-W5S06Q5J EVER BEEN DX PANIC/ANXIETY DIS-W4S26Q18H 12 MO,PULL KNIKE/GUN SOMEONE-W3S31Q8 SHOT/STABBED SOMEONE-W1S12Q13 PAST 7 DAYS PEOPLE DISLIKED U-W3S21Q20 12 MO,SHOT/STABBED SOMEONE-W4S31Q7 PULLED A KNIFE/GUN ON SOMEONE-W1S5Q6I EVER BEEN DX PANIC/ANXIETY DIS-W5ldlS31Q1 SAW SHOOTING/STABBING OF PERSON-W1S14Q25 PAST 7 DAYS ENJOYED LIFE-W4S21Q19 12 MO,PULL KNIFE/GUN SOMEONE-W4S14Q19 PAST 7 DAYS SHAKE OFF BLUES-W4S10Q0C PAST 7 DAY HAPPY-W5S21Q14 12 MO,SAW ONE SHOOT/STAB PERS-W4S14Q24 PAST 7 DAYS FELT HAPPY-W4S14Q23 PAST 7 DAYS FELT TOO TIRED-W4S10Q19 LIFE NOT WORTH LIVING-W1S29Q12 SELL DRUGS-W1S5Q2 FREQ-SKIPPED SCHOOL-W1S5Q9 EXPELLED FROM SCHOOL-W1S29Q11 USE OR THREATEN WITH A WEAPON-W1S38Q14 CHANCES-KILLED BY AGE 21-W1S10Q7 TOO TIRED TO DO THINGS-W1S29Q14 TAKE PART IN A GROUP FIGHT-W1S26Q6 12 MO,OFT STEAL SOMETHING/<$50-W3S10Q6 FELT DEPRESSED-W1S06Q5H EVER BEEN DX WITH DEPRESSION-W4S14Q3 LST MNTH UNABLE CONTROL THINGS-W4S14Q5 LST MNTH THINGS GOING YOUR WAY-W4S14Q4 LST MNTH CONF HANDLE PERS PROB-W4S10Q11 HAPPY-W1S10Q0D PAST 7 DAY SAD-W5BIOLOGICAL SEX-W1S14Q2B 12 MO SAW ONE SHOOT/STAB PERS-W5S15Q56 CHANCE OF-LIVING TILL AGE 35-W3S38Q12 CHANCES-LIVE TO AGE 35-W1S29Q13 STEAL WORTH < $50-W1S26Q30 DO NOT WORRY ABOUT PAST-W4S10Q17 FELT PEOPLE DISLIKE YOU-W1S26Q6 WORRY ABOUT THINGS-W4S26Q14 NOT EASILY BOTHERED BY THINGS-W4S10Q3 HAD THE BLUES-W1S10Q16 FELT SAD-W1S12Q8 PAST 7 DAYS TROUBLE CONCENTRTNG-W3S10Q4 JUST AS GOOD AS OTHER PEOPLE-W1S26Q23 EXPECT MORE GOOD THAN BAD-W4S12Q11 PAST 7 DAYS ENJOYED LIFE-W3S12Q7 PAST 7 DAYS FELT AS GOOD AS OTH-W3tgS12Q10 PAST 7 DAYS TOO TIRED DO THNGS-W3S12Q5 PAST 7 DAYS BOTHERED BY THINGS-W3S26Q22 I GET STRESSED OUT EASILY-W4S13Q3 LAST MO FELT THINGS GO YOUR WAY-W5S12Q1 PAST 7 DAYS SHAKE OFF BLUES-W3S12Q9 PAST 7 DAYS WERE DEPRESSED-W3S10Q15 ENJOYED LIFE-W1S26Q7 ALWAYS OPTIMISTIC ABOUT FUTURE-W4S13Q4 LAST MO DIFFS OVERWHELM-W5S26Q31 RARELY EXPECT GOOD HAPPN TO ME-W4S14Q2 HOW OFTEN FEEL ISOLATED-W4S27 BMI -W4S26Q5 12 MO,OFT SELL DRUGS-W3S9Q3 EXPECT MORE GOOD-W5S27 DIASTOLIC BLOOD PRESSURE -W4S27 SYSTOLIC BLOOD PRESSURE-W4S10Q5 TROUBLE KEEPING MIND FOCUSED-W1h3bmicrpS30Q9 DRIVE WHILE DRUNK-W1S27 MEASURED WAIST (CM) -W4S9Q2 NOT EXPECT THINGS MY WAY-W5S27 BLOOD PRESSURE CLASS -W4S9Q1 ALWAYS OPTIM ABOUT FUT-W5hdlS10Q1 BOTHERED BY THINGS-W1S14Q18 PAST 7 DAYS BOTHERED BY THINGS-W4S14Q22 PAST 7 DAYS FELT DEPRESSED-W4hba1cS12Q12 PAST 7 DAYS WERE SAD-W3S14Q6 LST MNTH DIFFICULTIES OVERWHELM-W4S14Q21 PAST 7 DAYS TROUBL CONCENTRTNG-W4S26Q15 DO NOT EXPECT THINGS MY WAY-W4S13Q2 LAST MO CONFID HANDLE PERS PBMS-W5S5Q7 RECEIVED OUT-OF-SCHL SUSPENSION-W1S22Q17 EVER INCARCERATED-W4age_w5S29Q3 LIE TO PARENTS ABOUT WHEREABOUT-W1one_race5S14Q26 PAST 7 DAYS FELT SAD-W4S10Q0B PAST 7 DAY DEPRESSED-W5S28Q49 SINCE JUN95 HAVE DRIVEN DRUNK-W3
overall_rank.lassooverall_rank.rfPermutation Importance of Predictors: Random Forest vs LassoPlacementsPredictorsmodel

With the final models generated, we’re now able to compare their performance metrics.

# Comparison of performance metrics
valid_perf <- get_metric_set_from_perfs(perf_list = list(final_rf_perf, final_lasso_perf)) %>%
  mutate(model = c('rf', 'lasso'))

testing_perf <- get_metric_set_from_models(testing_df, list(final_model_rf, final_model_lasso), out=outcome) %>%
  mutate(model = c('rf', 'lasso'))

Validation and selection. The following table shows the comparison between models in terms of the validation set. We can select our final model based on the best performing model according to the metric.

print(valid_perf)
ABCDEFGHIJ0123456789
model
<chr>
accuracy
<dbl>
kap
<dbl>
sens
<dbl>
spec
<dbl>
rf0.78401730.18898560.44791670.8228916
lasso0.79697620.18527120.40625000.8421687

Testing performance. The following shows the performance of both the models on the test set. Note that although we don’t use this test set to evaluate the final models, we can still see how our selected method would have performed.

print(testing_perf)
ABCDEFGHIJ0123456789
model
<chr>
accuracy
<dbl>
kap
<dbl>
sens
<dbl>
spec
<dbl>
rf0.78833690.16211470.38541670.8349398
lasso0.78833690.12660010.32291670.8421687

The following plots show a comparison between the performance of the models on the validation and test sets. Again, we don’t choose the model based on the test set, but curiosity dictates that we view this performance.

# Show plots side by side
metrics_of_interest = c('model', 'accuracy', 'bal_accuracy', 'mpce', 'sens', 'spec', 'ppv', 'npv', 'pr_auc', 'roc_auc')
valid_plt <- plot_metric_set(dplyr::select(valid_perf, all_of(metrics_of_interest)), plot_title = "Model comparison for validation set")
test_plt <- plot_metric_set(dplyr::select(testing_perf, all_of(metrics_of_interest)), plot_title = "Model comparison for testing set")
gridExtra::grid.arrange(gridExtra::arrangeGrob(valid_plt, test_plt, ncol=2, nrow=1))

Other cleanup

h2o.shutdown(FALSE)
LS0tCnRpdGxlOiAiODUtaW50ZXJwcmV0LWhlYXZ5LWRyaW5rIgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgdGhlbWU6IGx1bWVuCiAgICB0b2M6IHllcwogICAgdG9jX2Zsb2F0OiB5ZXMKICAgIHRvY19kZXB0aDogNAogIGh0bWxfZG9jdW1lbnQ6CiAgICBkZl9wcmludDogcGFnZWQKICAgIHRvYzogeWVzCmVkaXRvcl9vcHRpb25zOgogIGNodW5rX291dHB1dF90eXBlOiBpbmxpbmUKLS0tCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFKQpgYGAKCmBgYHtyIHNvdXJjZSBmaWxlcywgaW5jbHVkZT1GQUxTRX0Kc291cmNlKCJmdW5jdGlvbl9pbXBvcnQuUiIpCmBgYAoKIyMgUHJvamVjdCBydW4gcGFyYW1ldGVycwpgYGB7ciBzZWVkcyBmb3IgcmVwcm9kdWNpYmlsaXR5fQpub190YXNrcz0yCnNlZWQgPSA5Mzg0Cm91dGNvbWUgPSAnaHZfZHJpbmsnCmZiYXNlID0gJy9zY3JhdGNoL3BfZ2F5ZG9zaF9sYWIvRFNJLycKcmVzdWx0c19kaXJlY3RvcnkgPC0gc3RyX2MoZmJhc2UsIG91dGNvbWUsICcvcmVzdWx0c19mdWxsX2gyb18yJykKc2V0LnNlZWQoc2VlZCkKYGBgCgoqKlB1cnBvc2UuKiogSW4gdGhpcyB3b3JrLCB3ZSB3aWxsIGV4cGxvcmUgdGhlIHJlbGF0aW9uIGJldHdlZW4gaWRlbnRpZmllZCBtZWFzdXJlcyBvZiBkZXNwYWlyIG9mIGludGVyZXN0IChlLmcuLCBwZXJzb25hbGl0eSBtZWFzdXJlcyBvZiBzZWxmLWNvbnNjaW91c25lc3MsIGluZGl2aWR1YWwgYW5kIGNvbXBvc2l0ZSBpdGVtIHNjb3JlcyBmcm9tIHRoZSBDRVMtRCBhc3Nlc3NtZW50KSBhbmQgZGVzY3JpcHRvcnMgb2YgZGlzZWFzZXMgb2YgZGVzcGFpci4gIFdlIHdpbGwgYWNoaWV2ZSB0aGlzIGdvYWwgdGhyb3VnaCBtb2RlbGluZyB0aGUgb3V0Y29tZXMgYmFzZWQgb24gdGhlIGluY2x1ZGVkIHByZWRpY3RvcnMsIGFuZCByb2J1c3RseSBhc3Nlc3MgdGhlIGltcG9ydGFuY2Ugb2YgdGhlIGluY2x1ZGVkIGZlYXR1cmVzIGluIHByZWRpY3RpbmcgdGhlIG91dGNvbWVzIHZpYSBib290c3RyYXBwaW5nLiAgV2Ugd2lsbCB1c2UgdHdvIHdlbGwta25vd24gbWFjaGluZSBsZWFybmluZyBtb2RlbHMsIHJhbmRvbSBmb3Jlc3RzIGFuZCBMQVNTTywgd2hpY2ggYXJlIGJvdGggZnJlcXVlbnRseSB1c2VkIHRvIG1lYXN1cmUgdGhlIHJlbGF0aXZlIGltcG9ydGFuY2Ugb2YgdGhlIHByZWRpY3RvcnMgaW5jbHVkZWQgaW4gdGhlIG1vZGVscy4gIExhc3RseSwgd2UnbGwgZ2VuZXJhdGUgdHJhaW5lZCBhbmQgdHVuZWQgbW9kZWxzIHVzaW5nIHRoaXMgcmVkdWNlZCBmZWF0dXJlIHNldCB3aGljaCBjYW4gYmUgdXNlZCBieSBvdGhlcnMgd2lzaCB0byBwcmVkaWN0IHRoZSBpZGVudGlmaWVkIG91dGNvbWVzLgoKKipTdWJqZWN0IGluY2x1c2lvbi4qKiBGb3IgdGhpcyBpbnZlc3RpZ2F0aW9uLCB3ZSB3aWxsIG9taXQgdGhlIGVudGlyZXR5IG9mIFdhdmUgMi4gIFRoaXMgaXMgY29tbW9ubHkgZG9uZSBpbiBhbmFseXNlcyBvZiBBZGRIZWFsdGggZGF0YSBkdWUgdGhlIGRlc2lnbiBvZiB0aGUgb3JpZ2luYWwgc3R1ZHkuICBPdGhlcndpc2UsIG91ciBkYXRhc2V0IHdpbGwgaW5jbHVkZSBvbmx5IHN1YmplY3RzIHdobyBoYXZlIHByZWRpY3RvciBhbmQgb3V0Y29tZSBkYXRhIGluIF9hbGxfIG9mIHRoZSB3YXZlcy4KCioqT3V0Y29tZSB2YXJpYWJsZXMuKiogSW4gdGhpcyBleHBlcmltZW50LCB3ZSBhc3Nlc3MgX3N1aWNpZGFsIGlkZWF0aW9uXyBhdCBXYXZlIDUuICAKCioqUHJlZGljdG9yIHZhcmlhYmxlcy4qKiBUaGUgcHJlZGljdG9ycyBmb3IgdGhlc2UgbW9kZWxzIGFyZSBoYW5kLXBpY2tlZCwgYW5kIGJhc2VkIG9uIHByZXZpb3VzIHdvcmssIHJlbGV2YW5jZSwgYW5kIHN1YmplY3QgbWF0dGVyIGV4cGVydGlzZS4gVGhlIHNldCBvZiBwcmVkaWN0b3JzIGFuZCB0aGUgc2V0IG9mIG91dGNvbWVzIGFyZSBkaXNqb2ludC4gIFByZWRpY3RvcnMgZnJvbSBXYXZlcyAxLTQgKGV4Y2x1ZGluZyBXYXZlIDIsIHNlZSBhYm92ZSkgYXJlIGluY2x1ZGVkLCBhbmQgd2lsbCBiZSBkZXRhaWxlZCBpbiB0aGUgZm9sbG93aW5nIGFuYWx5c2lzLgoKYGBge3IgbG9hZCBsaWJyYXJpZXMsIGluY2x1ZGU9RkFMU0V9CiMgVXNlIHBhY21hbiwgd2hpY2ggZm9yY2VzIGFuIGluc3RhbGwgaWYgdGhlIGxpYnJhcnkgaXNuJ3QgcHJlc2VudCBvbiB0aGUgcnVubmluZyBtYWNoaW5lCmlmICghcmVxdWlyZSgicGFjbWFuIikpIGluc3RhbGwucGFja2FnZXMoInBhY21hbiIpCiNwYWNtYW46OnBfaW5zdGFsbChwbG90bHkpCnBhY21hbjo6cF9sb2FkKHRpZHl2ZXJzZSwgaDJvLCBmdXJycikKCmBgYAoKYGBge3IgaW5pdGlhbGl6YXRpb25zLCBpbmNsdWRlPUZBTFNFfQpwb3J0X25vIDwtIHN0YXJ0X2gybygpCmgyby5ub19wcm9ncmVzcygpCmZ1dHVyZTo6cGxhbihtdWx0aXByb2Nlc3MpCmBgYAoKIyBQaXBlbGluZSBvdmVydmlldwpgYGB7ciBlY2hvPUZBTFNFLCBvdXQud2lkdGg9JzUwJSd9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCcuL2ltZy9waXBlbGluZV9vdmVydmlldy5qcGcnKQpgYGAKCiMgRGF0YXNldCBnZW5lcmF0aW9uCgpUaGUgcHJlZGljdG9ycyB3ZSB3aWxsIGJlIHVzaW5nIHdpbGwgYmUgdGhlIHRoZSB2YXJpYWJsZSBgcHJlZGljdG9yX2xpc3RgIGxvYWRlZCBmcm9tIGAxMC1pbXBvcnQtZGF0YS5SbWRgIGZpbGUuIFRoZXNlIGluaXRpYWwgc2V0IG9mIHByZWRpY3RvcnMgd2lsbCBiZSBiYXNlZCBvZiB0aGUgbGlzdCBvZiB2YXJpYWJsZXMgdGhhdCBkZXNjcmliZSBhbnhpZXR5LCBkZXByZXNzaW9uLCBhbmQgb3B0aW1pc20uCgpgYGB7ciBsb2FkIHJhdyBkYXRhIGFuZCBmb3JtdWxhdGUgZGF0YXNldCwgd2FybmluZz1UUlVFLCBtZXNzYWdlPVRSVUV9CiMjIHNldCBvdXRjb21lIHZhcmlhYmxlIG9mIGludGVyZXN0CmZpbGViYXNlID0gJy9zY3JhdGNoL3BfZ2F5ZG9zaF9sYWInCgojY3JlYXRlIGRhdGEgaW4gc3BlY2lmaWVkIGZvcm0KZGF0YXNldF9saXN0IDwtIGdlbmVyYXRlX2RhdGFzZXRzKG91dGNvbWUsIGJpbmFyaXplPUZBTFNFLCBmaWxlYmFzZT1maWxlYmFzZSwgc2VlZF92YWw9c2VlZCkKCiNwYXJzZSBvdXQgZGF0YXNldCBjb21wb25lbnRzCndhdmVfZGF0YSA8LSBkYXRhc2V0X2xpc3Qkd2F2ZV9kYXRhCmZ1bGxfZGF0YXNldCA8LSBkYXRhc2V0X2xpc3QkZnVsbF9kYXRhc2V0CmRzX3JhdyA8LSBkYXRhc2V0X2xpc3QkZHNfcmF3X291dGNvbWUKZHMgPC0gZGF0YXNldF9saXN0JGRzX2ZpbmFsCgojbWwgc3BsaXRzIG9mIHRoZSBkYXRhCnRyYWluaW5nX2RmIDwtIGRhdGFzZXRfbGlzdCR0cmFpbmluZ19kZgp2YWxpZGF0aW9uX2RmIDwtIGRhdGFzZXRfbGlzdCR2YWxpZGF0aW9uX2RmCnRlc3RpbmdfZGYgPC0gZGF0YXNldF9saXN0JHRlc3RpbmdfZGYKCmBgYAoKIyMgT3V0Y29tZSB2YXJpYWJsZTogQmluYXJpemluZyBhbmQgcmVjb2RpbmcgZGV0YWlscwoKVGhlIGZvbGxvd2luZyB0YWJsZSBkZXRhaWxzIHRoZSB2YWx1ZXMgcHJlc2VudCBpbiB0aGUgb3V0Y29tZSB2YXJpYWJsZS4gIEFzIHdlIGNhbiBzZWUsIHdlIG5lZWQgdG8gY29udmVydCB0aGUgdmFyaWFibGUgaW50byBhIGZhY3RvciwgYW5kIGRyb3AgdGhlIE5Bcy4KCmBgYHtyIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9CmRzX3JhdyAlPiUgCiAgZ3JvdXBfYnkoLmRhdGFbW291dGNvbWVdXSkgJT4lIAogIHN1bW1hcmlzZSh0b3RhbCA9IG4oKSwgdHlwZSA9IGNsYXNzKC5kYXRhW1tvdXRjb21lXV0pKQoKZHMgJT4lIAogIGdyb3VwX2J5KC5kYXRhW1tvdXRjb21lXV0pICU+JSAKICBzdW1tYXJpc2UodG90YWwgPSBuKCksIHR5cGUgPSBjbGFzcyguZGF0YVtbb3V0Y29tZV1dKSkKCnByaW50KHN0cl9jKCdUb3RhbCBudW1iZXIgb2Ygc3ViamVjdHMgaW4gdW5wcm9jZXNzZWQgb3V0Y29tZSBkYXRhOiAnLCBucm93KGRzX3JhdykpKQpwcmludChzdHJfYygnVG90YWwgbnVtYmVyIG9mIHN1YmplY3RzIGluIHByb2Nlc3NlZCBvdXRjb21lIGRhdGE6ICcsIG5yb3coZHMpKSkKcHJpbnQoc3RyX2MoJ1RvdGFsIHN1YmplY3RzIGRyb3BwZWQgZHVlIHRvIE5BIG9yIHNraXA6ICcsIG5yb3coZHNfcmF3KS1ucm93KGRzKSkpCgpgYGAKClRoZSB0YWJsZSBhbHNvIGRlbW9uc3RyYXRlcyB0aGF0IHRoZSBjbGFzc2VzIGFyZSB2ZXJ5IGltYmFsYW5jZWQsIHdpdGggYWJvdXQgMTR4IHRoZSBuZWdhdGl2ZSBjbGFzcyBhcyBjb21wYXJlZCB3aXRoIHRoZSBwb3NpdGl2ZSBjbGFzcy4gIFRoaXMgaXMgZGlzcGxheWVkIGdyYXBoaWNhbGx5IGZvciBlYXN5IGNvbnN1bXB0aW9uIGJlbG93LgoKYGBge3IgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9MTAsIHdhcm5pbmc9VFJVRX0KZHNfcmF3ICU+JQogIGV4cGxvcmVfb3V0Y29tZShkcywgb3V0Y29tZSkKCmBgYAoKQWZ0ZXIgZHJvcHBpbmcgdGhlIE5Bcywgd2Ugc2VlIHRoYXQgd2Ugbm93IGhhdmUgOTE2OCByb3dzLCB3aGljaCBpcyBjb25zaXN0ZW50IHdpdGggdGhlIHRhYmxlIGFib3ZlLiAgVGhlIGRpc3RyaWJ1dGlvbiBvZiB0aGUgZGF0YSBoYXMgYSBkaXN0aW5jdCBpbWJhbGFuY2UgYXMgbm90ZWQgYWJvdmUuICBJIHRoaW5rIHRoaXMgd2FycmFudHMgdXNpbmcgYHByX2F1Y2AgYXMgdGhlIG9wdGltaXphdGlvbiBhbmQgc2VsZWN0aW9uIG1ldHJpYy4KCiMgRGF0YSBleHBsb3JhdGlvbiBhbmQgdmlzdWFsaXphdGlvbgpIZXJlLCB3ZSBjb21tZW50IGFib3V0IHRoZSBnZW5lcmFsIGNoYXJhY3RlcmlzdGljcyBvZiB0aGUgZGF0YSBiYXNlZCBvbiB0aGUgcHJvdmlkZWQgdmlzdWFsaXphdGlvbnMuICBXZSBjb21tZW50IG9uIG1pc3NpbmduZXNzIG9mIGRhdGEsIGFueSBzdHJhbmdlIG9yIHVudXN1YWwgYmVoYXZpb3IgKGUuZy4sIHN0cm9uZyBpbWJhbGFuY2VzKSwgYW5kIGFueSBjb3JyZWxhdGlvbiB0aGF0IHN0aWNrcyBvdXQuCgpgYGB7ciB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQojUmVwb3J0IGFib3V0IHRoZSBjaGFyYWN0ZXJpc3RpY3Mgb2YgdGhlIHN1YmplY3RzIGxlZnQgb3V0IG9mIHRoZSBqb2luCmRzICU+JSBleHBsb3JlX2Ryb3BwZWQoKQoKYGBgCgpgYGB7ciBlZGEgZGlzdHJpYnV0aW9ucywgZmlnLndpZHRoID0gMTUsIGZpZy5oZWlnaHQ9MTV9CiMgVmlzdWFsaXplIGRpc3RyaWJ1dGlvbnMgb2YgdmFyaWFibGVzIG9mIGludGVyZXN0CmRzICU+JSAKICBkcGx5cjo6c2VsZWN0KC1haWQpICU+JQogIGdyYXBoX2Jhcl9kaXNjcmV0ZShkZiA9IC4sCiAgICAgICAgICAgICAgICAgICAgIHBsb3RfdGl0bGUgPSAiRGlzdHJpYnV0aW9ucyBvZiBEaXNjcmV0ZSBWYXJpYWJsZXMiLAogICAgICAgICAgICAgICAgICAgICBtYXhfY2F0ZWdvcmllcyA9IDUwLAogICAgICAgICAgICAgICAgICAgICBudW1fcm93cyA9IDMsCiAgICAgICAgICAgICAgICAgICAgIG51bV9jb2xzID0gMywKICAgICAgICAgICAgICAgICAgICAgeF9heGlzX3NpemUgPSAxMiwKICAgICAgICAgICAgICAgICAgICAgeV9heGlzX3NpemUgPSAxMiwKICAgICAgICAgICAgICAgICAgICAgdGl0bGVfc2l6ZSA9IDE1KQpgYGAKCmBgYHtyIGVkYSBtaXNzaW5nfQpkcyAlPiUKICBncmFwaF9taXNzaW5nKG9ubHlfbWlzc2luZyA9IFRSVUUsCiAgICAgICAgICAgICAgICB0aXRsZSA9ICJQZXJjZW50IE1pc3NpbmciLAogICAgICAgICAgICAgICAgYm94X2xpbmVfc2l6ZSA9IC41LAogICAgICAgICAgICAgICAgbGFiZWxfc2l6ZSA9IC41LAogICAgICAgICAgICAgICAgeF9heGlzX3NpemUgPSAxMiwKICAgICAgICAgICAgICAgIHlfYXhpc19zaXplID0gMTIsCiAgICAgICAgICAgICAgICB0aXRsZV9zaXplID0gMTUpCgpgYGAKCmBgYHtyIGVkYSBjb3JyZWxhdGlvbnN9CmRzICU+JQogICNkcGx5cjo6c2VsZWN0KDE6MjApICU+JQogIHBhaXJ3aXNlX2NyYW1lcnNfdigpICU+JQogIHBsb3RfY3JhbWVyX3YoeF9heGlzX2FuZ2xlID0gOTAsCiAgICAgICAgICAgICAgICBwbG90X3RpdGxlID0gIkFzc29jaWF0aW9uIGFtb25nIENhdGVnb3JpY2FsIFZhcmlhYmxlcyIsCiAgICAgICAgICAgICAgICBpbnRlcmFjdGl2ZSA9IFRSVUUpCmBgYApUaGUgY29ycmVsYXRpb24gcGxvdCBzdWdnZXN0cyB0aGF0IHRoZXJlIGFyZSBzZXZlcmFsIHZhcmlhYmxlcyB3ZSBtaWdodCB0aGluayBhYm91dCByZW1vdmluZy4gIEZpcnN0bHksIHRoZXJlIGFyZSBtb2RlcmF0ZSBjb3JyZWxhdGlvbnMgYW1vbmcgdGhlIGluZGl2aWR1YWwgcHJlZGljdG9yIGJsb2NrczsgdGhpcyBpcyBkdWUgdG8gdGhlIHdheSB0aGF0IHRoZXkgYXJlIG9yZGVyZWQsIHNpbmNlIHRoZXkncmUgZXNzZW50aWFsbHkgZ3JvdXBlZCBpbnRvIHN1YnNldHMuICBBZGR0aW9uYWxseSwgc29tZSBwcmVkaWN0b3IgcGFpcnMgaGF2ZSBleHRyZW1lbHkgaGlnaCBjb3JyZWxhdGlvbnMsIGxpa2UgKGg0aWQ1aiwgaDRtaDI2KSAoY29ycmVsYXRpb24gb2YgMC43MiksIGFuZCBtYW55IHZhcmlhYmxlcyBpbiB0aGUgaDRtaCogc2VyaWVzLiAgKGgzaWQ1aiwgaDRpZDVoKSBhbHNvIGhhcyBoaWdoIGNvcnJlbGF0aW9uID4gMC41LiAgV2UgbWF5IHdhbnQgdG8gY29uc2lkZXIgcmVtb3Zpbmcgc2V2ZXJhbCBvZiB0aGVzZSBpbiBhZGRpdGlvbiB0byB0aGUgYWdlIHZhcmlhYmxlcyBiZWNhdXNlIGl0IG1heSBjYXVzZSBmZWF0dXJlIGltcG9ydGFuY2UgbWFza2luZyB3aXRoaW4gb3VyIGFwcHJvYWNoZXMuCgojIFJvYnVzdCBmZWF0dXJlIGV2YWx1YXRpb24gey50YWJzZXQgLnRhYnNldC1mYWRlIC50YWJzZXQtcGlsbHN9CgpUaGUgZm9sbG93aW5nIHRhYmxlIGRpc3BsYXlzIHRoZSBtZWFuIHBlcmZvcm1hbmNlIG1ldHJpY3MgZm9yIHRoZSBib290c3RyYXBwZWQgbW9kZWxzIG9uIHRoZSB2YWxpZGF0aW9uIHNldCwgcmVtb3ZpbmcgdmFsdWVzIGZvciB3aGljaCB0aGVyZSBhcmUgTkEuCgpgYGB7ciBzYXZlL2xvYWQgcmYgYm9vdHN0cmFwIG1vZGVsIHBlcmZvcm1hbmNlLCBpbmNsdWRlPUZBTFNFfQoKYnNfcmZfcGVyZiA9IE5VTEwKCiMgZ2V0IGRhdGEgZmlsZXMKYnNfcmZfcGVyZiA9IGxvYWRfZnJvbV9jc3YoYnNfcmZfcGVyZiwgcmVzdWx0c19kaXJlY3RvcnksIG5vX3Rhc2tzKQoKYGBgCgoKYGBge3IgZXZhbHVhdGUgYm9vdHN0cmFwIG1vZGVsIHBlcmZvcm1hbmNlIHJmLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQoKbWVhbl9ic19yZl9wZXJmIDwtIGJzX3JmX3BlcmYgJT4lCiAgc3VtbWFyaXNlX2lmKGlzLm51bWVyaWMsIG1lYW4sIG5hLnJtPVRSVUUpICU+JQogIG11dGF0ZShtb2RlbCA9ICdic19yZicpICU+JQogIGRwbHlyOjpzZWxlY3QobW9kZWwsIGV2ZXJ5dGhpbmcoKSkKCm1lYW5fYnNfcmZfcGVyZgpgYGAKQXMgc2hvd24sIHRoZSBib290c3RyYXBwZWQgbW9kZWxzIHRlbmQgdG8gaGF2ZSBoaWdoIHNwZWNpZmljaXR5IGJ1dCBsb3cgc2Vuc2l0aXZpdHksIGluZGljYXRpbmcgdGhhdCB0aGVyZSBpcyBhIGNoYWxsZW5nZSBpbiBpZGVudGlmeWluZyBzdWJqZWN0cyB3aXRoIHN1aWNpZGFsIGlkZWF0aW9uLgoKIyMjIEZlYXR1cmUgaW1wb3J0YW5jZXM6IFJhbmRvbSBGb3Jlc3QKIyMjIyBNZWFuIGRlY3JlYXNlIGluIGltcHVyaXR5IChNREkpCgpgYGB7ciBzYXZlL2xvYWQgcmYgYm9vdHN0cmFwIG1vZGVsIG1kaSwgaW5jbHVkZT1GQUxTRX0KCmJzX3JmX21kaSA9IE5VTEwKICAKIyBnZXQgZGF0YSBmaWxlcwpic19yZl9tZGkgPSBsb2FkX2Zyb21fY3N2KGJzX3JmX21kaSwgcmVzdWx0c19kaXJlY3RvcnksIG5vX3Rhc2tzKQoKCmBgYAoKYGBge3IgZXZhbHVhdGUgYm9vdHN0cmFwIG1kaX0KYm9vdF9yZl9tZGkgPC0gbGlzdChic19yZl9tZGkpICU+JQogIGdldF9tZWRpYW5fcGxhY2VtZW50KHVzZV9iYXNlX3ZhciA9IFRSVUUpICU+JQogIGFkZF9hdHRyaWJ1dGVfbmFtZXMoJ3ByZWRpY3RvcicsIGZ1bGxfZGF0YXNldCkgJT4lCiAgZHBseXI6OnNlbGVjdChwcmVkaWN0b3IsIGF0dF9uYW1lLCBvdmVyYWxsX3JhbmspCgpoZWFkKGJvb3RfcmZfbWRpLCAyMCkKYGBgClRoaXMgdGFibGUgcmV0dXJucyB0aGUgTURJIHZhcmlhYmxlIGltcG9ydGFuY2UgcmFua3MgdGhhdCByZXR1cm5lZCBmcm9tIGVhY2ggb2YgdGhlIGJvb3RzdHJhcHBlZCBtb2RlbHMuCgpgYGB7ciBmaWcud2lkdGggPSAxMCwgZmlnLmhlaWdodCA9IDEyfQojIE5lZWRzIHRvIGJlIGZpeGVkIHNvIHRoYXQgYXhlcyBkb24ndCBvdmVybGFwIGVhY2ggb3RoZXIgYW5kIG9ic2N1cmUgdW5kZXJzdGFuZGluZwpwbG90X3BsYWNlbWVudF9ib3hwbG90KGxpc3QoYnNfcmZfbWRpKSkKYGBgCgojIyMjIFBlcm11dGF0aW9uIGltcG9ydGFuY2UKTm93LCBsZXQncyBsb29rIGF0IHRoZSBwZXJtdXRhdGlvbiBpbXBvcnRhbmNlOgoKYGBge3IgY29tcHV0ZS9zYXZlIG9yIGxvYWQgYnMgcmYgbW9kZWwgcGVybXV0YXRpb24sIGluY2x1ZGU9RkFMU0V9Cgpic19yZl9wZXJtX3BsdCA8LSBOVUxMCiAgCiMgZ2V0IGRhdGEgZmlsZXMKYnNfcmZfcGVybV9wbHQgPC0gbG9hZF9mcm9tX2Nzdihic19yZl9wZXJtX3BsdCwgcmVzdWx0c19kaXJlY3RvcnksIG5vX3Rhc2tzKQoKYGBgCgoKYGBge3IgYWdncmVnYXRlIHJmIHBlcm0gcmVzdWx0c30KbWV0IDwtICdwcl9hdWMnCmJzX3JmX3Blcm0gPC0gYnNfcmZfcGVybV9wbHQgJT4lCiAgZ2V0X3Blcm11dGVfcGxhY2VtZW50KG1ldHJpY19vaT1tZXQpICU+JQogIGFkZF9hdHRyaWJ1dGVfbmFtZXMoJ3ByZWRpY3RvcicsIGZ1bGxfZGF0YXNldCkgJT4lCiAgZHBseXI6OnNlbGVjdChwcmVkaWN0b3IsIGV2ZXJ5dGhpbmcoKSkKCmhlYWQoYnNfcmZfcGVybSwgMjApCmBgYAoKIyMjIyBNREkgdnMgUGVybXV0YXRpb24gaW1wb3J0YW5jZQpJbiB0aGlzIHN0ZXAsIHdlIGFzc2VzcyB0aGUgZGlmZmVyZW5jZXMgZ2VuZXJhdGVkIGJldHdlZW4gdGhlIGRpZmZlcmVudCB0eXBlcyBvZiBpbXBvcnRhbmNlcy4KYGBge3IgZmlnLndpZHRoID0gMTYsIGZpZy5oZWlnaHQgPSAxNH0KY2JpbmQoYm9vdF9yZl9tZGlbMToyMCxdLCBkcGx5cjo6c2VsZWN0KGJzX3JmX3Blcm1bMToyMCxdLCAtYWxsX29mKG1ldCkpKQpgYGAKQXMgc2hvd24sIHRoZSBNREkgaW1wb3J0YW5jZSBzdWZmZXJzIGZyb20gaW1iYWxhbmNlcyBkdWUgdG8gdGhlIG51bWJlciBvZiB2YWx1ZXMgYXNzb2NpYXRlZCB3aXRoIGEgcHJlZGljdG9yLiAgQmVjYXVzZSB0aGUgd2F2ZSBhZ2VzIGhhdmUgc28gbWFueSBtb3JlIHZhbHVlcyB0aGFuIHRoZSBvdGhlciBmYWN0b3JzLCB0aGlzIGFydGlmaWNpYWxseSBpbmZsYXRlcyB0aGVpciBpbXBvcnRhbmNlIGluIE1ESS4gIFRoZSBwZXJtdXRhdGlvbiBpbXBvcnRhbmNlIGlzIG1vcmUgaW50dWl0aXZlLgoKYGBge3IgZmlnLndpZHRoID0gMTAsIGZpZy5oZWlnaHQgPSAxMn0KcGxvdF9wZXJtdXRlX3Zhcl9pbXAoYnNfcmZfcGVybSwgbWV0cmljID0gbWV0KQpgYGAKCgojIyBMQVNTTyBtb2RlbApJbiB0aGlzIHN0ZXAsIHdlIG1vZGVsIHRoZSByZWxhdGlvbiBiZXR3ZWVuIHRoZSBvdXRjb21lcyBhbmQgdGhlIHByZWRpY3RvcnMgdXNpbmcgYSBsaW5lYXIgcmVncmVzc2lvbiB3aXRoIEwyIHJlZ3VsYXJpemF0aW9uLiAgVGhpcyBkcml2ZXMgdGhlIGltcG9ydGFuY2Ugb2YgdW5pbXBvcnRhbnQgYW5kIHJlZHVkYW50IGZlYXR1cmVzIHRvd2FyZHMgemVyby4KCgpgYGB7ciBzYXZlL2xvYWQgbGFzc28gYm9vdHN0cmFwIG1vZGVsIHBlcmZvcm1hbmNlLCBpbmNsdWRlPUZBTFNFfQoKYnNfbGFzc29fcGVyZiA9IE5VTEwKICAKIyBnZXQgZGF0YSBmaWxlcwpic19sYXNzb19wZXJmID0gbG9hZF9mcm9tX2Nzdihic19sYXNzb19wZXJmLCByZXN1bHRzX2RpcmVjdG9yeSwgbm9fdGFza3MpCgoKYGBgCgpgYGB7ciBldmFsdWF0ZSBib290c3RyYXAgbW9kZWwgcGVyZm9ybWFuY2UgbGFzc28sIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9Cm1lYW5fYnNfbGFzc29fcGVyZiA8LSBic19sYXNzb19wZXJmICU+JQogIHN1bW1hcmlzZV9pZihpcy5udW1lcmljLCBtZWFuLCBuYS5ybT1UUlVFKSAlPiUgCiAgbXV0YXRlKG1vZGVsPSdic19sYXNzbycpICU+JQogIGRwbHlyOjpzZWxlY3QobW9kZWwsIGV2ZXJ5dGhpbmcoKSkKCm1lYW5fYnNfbGFzc29fcGVyZgpgYGAKCiMjIyBGZWF0dXJlIGltcG9ydGFuY2VzOiBMQVNTTwojIyMjIENvZWZmaWNpZW50LWJhc2VkIHZhcmlhYmxlIGltcG9ydGFuY2UKCmBgYHtyIHNhdmUvbG9hZCBsYXNzbyBib290c3RyYXAgbW9kZWwgbWRpLCBpbmNsdWRlPUZBTFNFfQoKYnNfbGFzc29fbWRpID0gTlVMTAogIAojIGdldCBkYXRhIGZpbGVzCmJzX2xhc3NvX21kaSA9IGxvYWRfZnJvbV9jc3YoYnNfbGFzc29fbWRpLCByZXN1bHRzX2RpcmVjdG9yeSwgbm9fdGFza3MpCgpgYGAKCmBgYHtyIHNob3cgYnMgbGFzc28gbm9ybWFsaXplZCBjb2VmZmljaWVudHN9CmJvb3RfbGFzc29fbWRpIDwtIGxpc3QoYnNfbGFzc29fbWRpKSAlPiUKICBnZXRfbWVkaWFuX3BsYWNlbWVudCh1c2VfYmFzZV92YXIgPSBUUlVFKSAlPiUKICBhZGRfYXR0cmlidXRlX25hbWVzKCdwcmVkaWN0b3InLCBmdWxsX2RhdGFzZXQpICU+JQogIGRwbHlyOjpzZWxlY3QocHJlZGljdG9yLCBhdHRfbmFtZSwgb3ZlcmFsbF9yYW5rKQoKaGVhZChib290X2xhc3NvX21kaSwgMjApCmBgYAoKYGBge3IgZmlnLndpZHRoID0gMTAsIGZpZy5oZWlnaHQgPSAxMn0KcGxvdF9wbGFjZW1lbnRfYm94cGxvdChsaXN0KGJzX2xhc3NvX21kaSkpCmBgYAoKIyMjIyBQZXJtdXRhdGlvbiBpbXBvcnRhbmNlCgpgYGB7ciBjb21wdXRlL3NhdmUgb3IgbG9hZCBicyBsYXNzbyBtb2RlbCBwZXJtdXRhdGlvbiwgaW5jbHVkZT1GQUxTRX0KCmJzX2xhc3NvX3Blcm1fcGx0ID0gTlVMTAogIAojIGdldCBkYXRhIGZpbGVzCmJzX2xhc3NvX3Blcm1fcGx0ID0gbG9hZF9mcm9tX2Nzdihic19sYXNzb19wZXJtX3BsdCwgcmVzdWx0c19kaXJlY3RvcnksIG5vX3Rhc2tzKQoKYGBgCgoKYGBge3IgYWdncmVnYXRlIGxhc3NvIHBlcm11dGF0aW9ucyBhbmQgZ2V0IG1ldHJpY3N9CmJzX2xhc3NvX3Blcm0gPC0gYnNfbGFzc29fcGVybV9wbHQgJT4lCiAgZ2V0X3Blcm11dGVfcGxhY2VtZW50KG1ldHJpY19vaT1tZXQpICU+JSAjc2V0IGluIHJhbmRvbSBmb3Jlc3Qgc2VjdGlvbgogIGFkZF9hdHRyaWJ1dGVfbmFtZXMoJ3ByZWRpY3RvcicsIGZ1bGxfZGF0YXNldCkgJT4lCiAgZHBseXI6OnNlbGVjdChwcmVkaWN0b3IsIGV2ZXJ5dGhpbmcoKSkKCmhlYWQoYnNfbGFzc29fcGVybSwgMjApCmBgYAoKYGBge3IgcGxvdCBsYXNzbyBwZXJtdXRhdGlvbiwgZmlnLndpZHRoID0gMTAsIGZpZy5oZWlnaHQgPSAxMn0KcGxvdF9wZXJtdXRlX3Zhcl9pbXAoYnNfbGFzc29fcGVybSwgbWV0cmljID0gbWV0KQpgYGAKCiMjIyMgQ29lZmZpY2llbnQgdnMuIFBlcm11dGF0aW9uIGltcG9ydGFuY2UKTm93LCB3ZSBjb21wYXJlIHRoZSBmZWF0dXJlIGltcG9ydGFuY2VzIGdlbmVyYXRlZCBieSB0aGUgdHdvIGRpZmZlcmVudCBhcHByb2FjaGVzLiAgVGhlIHRyYWRpdGlvbmFsIG1ldGhvZCBvZiBldmFsdWF0aW5nIGZlYXR1cmUgaW1wb3J0YW5jZSBmb3IgcmVncmVzc2lvbiBtZXRob2RzIGlzIHRocm91Z2ggYW5hbHlzaXMgb2YgdGhlIGNvZWZmaWNpZW50cy4KYGBge3IgZmlnLndpZHRoID0gMTYsIGZpZy5oZWlnaHQgPSAxNH0KY2JpbmQoYm9vdF9sYXNzb19tZGlbMToyMCxdLCBkcGx5cjo6c2VsZWN0KGJzX2xhc3NvX3Blcm1bMToyMCxdLCAtbWV0KSkKYGBgCgojIyBDb21wYXJpc29uOiBNb2RlbCBUeXBlIE1lYW4gUGVyZm9ybWFuY2UKVGhlIGZvbGxvd2luZyB0YWJsZSBjb21wYXJlcyB0aGUgbWVhbiBwZXJmb3JtYW5jZSBvZiBib290c3RyYXBwZWQgcmFuZG9tIGZvcmVzdHMgdG8gdGhlIG1lYW4gcGVyZm9ybWFuY2Ugb2YgYm9vdHN0cmFwcGVkIExBU1NPIG1ldGhvZHMuCmBgYHtyIGNvbXBhcmUgYnMgbWVhbiBwZXJmb3JtYW5jZX0KYnNfY29tcF9wZXJmcyA8LSBiaW5kX3Jvd3MobWVhbl9ic19yZl9wZXJmLCBtZWFuX2JzX2xhc3NvX3BlcmYpIApic19jb21wX3BlcmZzCmBgYAoKIyMgQ29tcGFyaXNvbjogTW9kZWwgVHlwZSBGZWF0dXJlIEltcG9ydGFuY2UKSGVyZSwgd2UgbG9vayBhdCB0aGUgYWdncmVnYXRlZCByZXN1bHRzIG9mIHRoZSBib290c3RyYXBwZWQgcHJlZGljdG9ycyBhbmQgY29tcGFyZSB0aGUgbW9kZWxzIGdlbmVyYXRlZCB0byBlYWNoIG90aGVyLgpgYGB7ciBjb21wcmUgYnMgZmVhdHVyZSBpbXBvcnRhbmNlfQpqb2luZWRfcmVzdWx0cyA8LSBic19yZl9wZXJtICU+JQogIGRwbHlyOjpzZWxlY3QoLW1ldCkgJT4lCiAgZnVsbF9qb2luKGRwbHlyOjpzZWxlY3QoYnNfbGFzc29fcGVybSwgLW1ldCksIGJ5PWMoInByZWRpY3RvciIsICJhdHRfbmFtZSIpLCBzdWZmaXg9YygnLnJmJywgJy5sYXNzbycpKSAlPiUKICBtdXRhdGUobWVhbl9yYW5rID0gKG92ZXJhbGxfcmFuay5yZitvdmVyYWxsX3JhbmsubGFzc28pLzIpICU+JQogIGFycmFuZ2UobWVhbl9yYW5rKQoKaGVhZChqb2luZWRfcmVzdWx0cywgMjApCmBgYAoKVGhlIGZvbGxvd2luZyB2aXN1YWxpemF0aW9uIHByb3ZpZGVzIHRoZSBpbnR1aXRpb24gYWJvdXQgdGhlIGRpZmZlcmVuY2VzIGluIHRoZSByYW5raW5ncyBiZXR3ZWVuIG1vZGVsIHR5cGVzLiAgVGhleSdyZSBvcmRlcmVkIGJ5IHRoZSBvdmVyYWxsIG1lYW4gaW1wb3J0YW5jZSwgYW5kIGZvciBhIGdpdmVuIHZhcmlhYmxlLCB0aGUgZGlmZmVyZW5jZXMgaW4gcmFuayBhcmUgc2hvd24uCmBgYHtyIGJzIGZlYXR1cmUgaW1wb3J0YW5jZSBwbG90bHksIGZpZy53aWR0aCA9IDE2LCBmaWcuaGVpZ2h0ID0gMTR9CiMgQ29tcGFyaXNvbiBvZiB0b3BfbiBmZWF0dXJlcwpqb2luZWRfcmVzdWx0cyAlPiUKICBjb21wYXJlX2ZlYXR1cmVfc2VsZWN0KGludGVyYWN0aXZlID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgIHRvcF9uID0gMTAwLAogICAgICAgICAgICAgICAgICAgICAgICAgb3BhY2l0eSA9IDAuNTAsCiAgICAgICAgICAgICAgICAgICAgICAgICBwbG90X3RpdGxlID0gIlBlcm11dGF0aW9uIEltcG9ydGFuY2Ugb2YgUHJlZGljdG9ycyBieSBNb2RlbCIpCmBgYAoKCiMgR2VuZXJhdGlvbiBvZiBmaW5hbCBtb2RlbCB7LnRhYnNldCAudGFic2V0LWZhZGUgLnRhYnNldC1waWxsc30KCiMjIFJGIG1vZGVsCkluIHRoaXMgc3RlcCwgd2UgYnVpbGQgdGhlIGZpbmFsIG1vZGVsIGZvciB0aGUgcmFuZG9tIGZvcmVzdC4gIFdlIHVzZSBzbGlnaHRseSBtb3JlIHZhbHVlcyBpbiBvcmRlciB0byBjb21lIHVwIHdpdGggdGhlIGJlc3QgbW9kZWwsIGtlZXBpbmcgaW4gbWluZCB0aGUgbnVtYmVyIG9mIGNvbWJpbmF0aW9ucyB0aGF0IGFyZSByZXF1aXJlZCB0byBydW4gdG8gZXZhbHVhdGUgdGhlIGdyaWQuCgpgYGB7ciBzYXZlL2xvYWQgZmluYWwgcmYgbW9kZWx9CgpmaW5hbF9yZl9wZXJmID0gTlVMTAogIAojIHJlYWQgZmlsZSBhcnJheQpmaW5hbF9yZl9wZXJmcyA9IGxvYWRfZnJvbV9jc3YoZmluYWxfcmZfcGVyZiwgcmVzdWx0c19kaXJlY3RvcnksIG5vX3Rhc2tzKQoKIyBnZXQgdGhlIGluZGV4IG9mIHRoZSBiZXN0IHBlcmZvcm1hbmNlIGFuZCBiZXN0IHBlcmZvcm1hbmNlCmZpbmFsX3JmbW9kZWxfaW5kIDwtIHdoaWNoLm1heChkcGx5cjo6c2VsZWN0KGZpbmFsX3JmX3BlcmZzLCBtZXQpICU+JSBwdWxsKG1ldCkpCmZpbmFsX3JmX3BlcmYgPC0gZmluYWxfcmZfcGVyZnMgJT4lIHNsaWNlKGZpbmFsX3JmbW9kZWxfaW5kKQoKIyBsb2FkIHRoZSBtb2RlbCBvZiBpbnRlcmVzdApmaW5hbF9tb2RlbF9yZiA8LSBsb2FkX2Jlc3RfbW9kZWwoJ2ZpbmFsX3JmX21vZGVsJywgcmVzdWx0c19kaXJlY3RvcnksIGZpbmFsX3JmbW9kZWxfaW5kKQoKYGBgCgojIyMgUGVyZm9ybWFuY2UKVGhlIGZpbmFsIHJhbmRvbSBmb3Jlc3QgcGVyZm9ybWFuY2UgbWV0cmljcyBhcmUgc2hvd24gYmVsb3c6CmBgYHtyIHJmIGZpbmFsIG1vZGVsIHBlcmZvcm1hbmNlfQojIHNob3cgbW9kZWwgZmluYWwgcGVyZm9ybWFuY2UKcHJpbnQoZmluYWxfcmZfcGVyZikKYGBgCgojIyMgRmVhdHVyZXM6IHBlcm11dGF0aW9uIGltcG9ydGFuY2UKCmBgYHtyIGNvbXB1dGUvc2F2ZSBvciBsb2FkIGZpbmFsIHJmIG1vZGVsIHBlcm11dGF0aW9ufQoKZmluYWxfcmZfcGVybV9wbHQgPSBOVUxMCiAgCiMgcmVhZCBiZXN0IHBlcm0gcGx0CmZpbmFsX3JmX3Blcm1fcGx0ID0gbG9hZF9mcm9tX2NzdihmaW5hbF9yZl9wZXJtX3BsdCwgcmVzdWx0c19kaXJlY3RvcnksIGJlc3RfaW5kPWZpbmFsX3JmbW9kZWxfaW5kKQoKYGBgCgoKYGBge3IgZ2V0IG1ldHJpY3MgZm9yIGZpbmFsIHJmfQpmaW5hbF9yZl9wZXJtIDwtIGZpbmFsX3JmX3Blcm1fcGx0ICU+JQogIGdldF9wZXJtdXRlX3BsYWNlbWVudChtZXRyaWNfb2k9bWV0KSAlPiUKICBhZGRfYXR0cmlidXRlX25hbWVzKCdwcmVkaWN0b3InLCBmdWxsX2RhdGFzZXQpICU+JQogIGRwbHlyOjpzZWxlY3QocHJlZGljdG9yLCBldmVyeXRoaW5nKCkpCgpoZWFkKGZpbmFsX3JmX3Blcm0sIDIwKQpgYGAKCmBgYHtyIHBsb3QgcmYgZmluYWwgcGVybXV0YXRpb24sIGZpZy53aWR0aCA9IDEwLCBmaWcuaGVpZ2h0ID0gMTJ9CnBsb3RfcGVybXV0ZV92YXJfaW1wKGZpbmFsX3JmX3Blcm0sIG1ldHJpYyA9IG1ldCkKYGBgCiMjIyBDb21wYXJpc29uIHdpdGggYm9vdHN0cmFwIHJlc3VsdHMKVGhpcyBzZWN0aW9uIGludmVzdGlnYXRlcyB0aGUgZGlmZmVyZW5jZXMgaW4gdGhlIGJvb3RzdHJhcCByZXN1bHRzIHZzIHRoZSBmZWF0dXJlcyBnZW5lcmF0ZWQgZnJvbSB0aGUgcmFuZG9tIGZvcmVzdCBmaW5hbCBtb2RlbC4gIFRoZSBmb2xsb3dpbmcgdGFibGUgc2hvd3MgdGhlIG92ZXJhbGwgZGlmZmVyZW5jZXMgaW4gcmFuay4KCmBgYHtyIGNvbXBhcmUgcmYgZmluYWwgd2l0aCBib290c3RyYXB9CnJmX2pvaW5lZF9yZXN1bHRzIDwtIGZpbmFsX3JmX3Blcm0gJT4lCiAgZHBseXI6OnNlbGVjdCgtbWV0KSAlPiUKICBmdWxsX2pvaW4oZHBseXI6OnNlbGVjdChic19yZl9wZXJtLCAtbWV0KSwgYnk9YygicHJlZGljdG9yIiwgImF0dF9uYW1lIiksIHN1ZmZpeD1jKCcuZmluYWwnLCAnLmJvb3RzdHJhcCcpKSAlPiUKICBtdXRhdGUobWVhbl9yYW5rID0gKG92ZXJhbGxfcmFuay5maW5hbCArIG92ZXJhbGxfcmFuay5ib290c3RyYXApLzIpICU+JQogIGFycmFuZ2UobWVhbl9yYW5rKQoKaGVhZChyZl9qb2luZWRfcmVzdWx0cywgMjApCmBgYAoKVGhlIGZvbGxvd2luZyBwbG90IHByb3ZpZGVzIHZpc3VhbGl6YXRpb25zIGZvciB0aGUgZGlmZmVyZW5jZSBpbiB0aGUgZmluYWwgbW9kZWwgcmFua2luZ3MgdnMgdGhlIGJvb3RzdHJhcC4KCmBgYHtyIHBsb3QgZmluYWwgcmYgZmVhdHVyZXMgcGxvdGx5LCBmaWcuaGVpZ2h0PTE0LCBmaWcud2lkdGg9MTZ9CiMgQ29tcGFyaXNvbiBvZiB0b3BfbiBmZWF0dXJlcwpyZl9qb2luZWRfcmVzdWx0cyAlPiUKICBjb21wYXJlX2ZlYXR1cmVfc2VsZWN0KHNlbF9jb2xzID0gYygib3ZlcmFsbF9yYW5rLmZpbmFsIiwgIm92ZXJhbGxfcmFuay5ib290c3RyYXAiKSwKICAgIGludGVyYWN0aXZlID0gVFJVRSwKICAgIHRvcF9uID0gMTAwLAogICAgb3BhY2l0eSA9IDAuNTAsCiAgICBwbG90X3RpdGxlID0gIlBlcm11dGF0aW9uIEltcG9ydGFuY2Ugb2YgUHJlZGljdG9yczogRmluYWwgdnMuIEJvb3RzdHJhcCIpCmBgYAoKIyMgTEFTU08gbW9kZWwKTm93LCB3ZSBjcmVhdGUgdGhlIGZpbmFsIG1vZGVsIGZvciBMQVNTTy4gIFRoZXJlIGlzIG5vIHN1YnN0YW50aWFsIGRpZmZlcmVuY2UgYmV0d2VlbiB0aGlzIG1ldGhvZCBhbmQgdGhlIGJvb3RzdHJhcCBtZXRob2RzLCBvdGhlciB0aGFuIHRoZSBkYXRhIHVwb24gd2hpY2ggdGhlIG1vZGVsIGlzIGJlaW5nIGJ1aWx0LgoKYGBge3Igc2F2ZS9sb2FkIGZpbmFsIGxhc3NvIG1vZGVsfQoKZmluYWxfbGFzc29fcGVyZiA9IE5VTEwKICAKIyByZWFkIGZpbGUgYXJyYXkKZmluYWxfbGFzc29fcGVyZnMgPSBsb2FkX2Zyb21fY3N2KGZpbmFsX2xhc3NvX3BlcmYsIHJlc3VsdHNfZGlyZWN0b3J5LCBub190YXNrcykKCiMgZ2V0IHRoZSBpbmRleCBvZiB0aGUgYmVzdCBwZXJmb3JtYW5jZSBhbmQgYmVzdCBwZXJmb3JtYW5jZQpmaW5hbF9sYXNzb21vZGVsX2luZCA8LSB3aGljaC5tYXgoZHBseXI6OnNlbGVjdChmaW5hbF9sYXNzb19wZXJmcywgbWV0KSAlPiUgcHVsbChtZXQpKQpmaW5hbF9sYXNzb19wZXJmIDwtIGZpbmFsX2xhc3NvX3BlcmZzICU+JSBzbGljZShmaW5hbF9sYXNzb21vZGVsX2luZCkKCiMgbG9hZCB0aGUgbW9kZWwgb2YgaW50ZXJlc3QKZmluYWxfbW9kZWxfbGFzc28gPC0gbG9hZF9iZXN0X21vZGVsKCdmaW5hbF9sYXNzb19tb2RlbCcsIHJlc3VsdHNfZGlyZWN0b3J5LCBmaW5hbF9sYXNzb21vZGVsX2luZCkKCmBgYAoKVGhlIGZpbmFsIExBU1NPIHBlcmZvcm1hbmNlIG1ldHJpY3MgYXJlIHNob3duIGJlbG93OgpgYGB7ciBsYXNzbyBmaW5hbCBtb2RlbCBwZXJmb3JtYW5jZX0KIyBzaG93IG1vZGVsIGZpbmFsIHBlcmZvcm1hbmNlCnByaW50KGZpbmFsX2xhc3NvX3BlcmYpCmBgYAoKIyMjIEZlYXR1cmVzOiBwZXJtdXRhdGlvbiBpbXBvcnRhbmNlCgpgYGB7ciBjb21wdXRlL3NhdmUgb3IgbG9hZCBmaW5hbCBsYXNzbyBtb2RlbCBwZXJtdXRhdGlvbn0KCmZpbmFsX2xhc3NvX3Blcm1fcGx0ID0gTlVMTAoKI2xvYWQgYmVzdCBpbmRleCBwZXJtdXRhdGlvbiBmcm9tIGZpbGUgIApmaW5hbF9sYXNzb19wZXJtX3BsdCA9IGxvYWRfZnJvbV9jc3YoZmluYWxfbGFzc29fcGVybV9wbHQsIHJlc3VsdHNfZGlyZWN0b3J5LCBiZXN0X2luZD1maW5hbF9sYXNzb21vZGVsX2luZCkKCgpgYGAKCmBgYHtyIGdldCBwZXJtdXRlIGZlYXR1cmVzIGZvciBmaW5hbCBsYXNzb30KZmluYWxfbGFzc29fcGVybSA8LSBmaW5hbF9sYXNzb19wZXJtX3BsdCAlPiUKICBnZXRfcGVybXV0ZV9wbGFjZW1lbnQobWV0cmljX29pPW1ldCkgJT4lCiAgYWRkX2F0dHJpYnV0ZV9uYW1lcygncHJlZGljdG9yJywgZnVsbF9kYXRhc2V0KSAlPiUKICBkcGx5cjo6c2VsZWN0KHByZWRpY3RvciwgZXZlcnl0aGluZygpKQoKaGVhZChmaW5hbF9sYXNzb19wZXJtLCAyMCkKYGBgCgpgYGB7ciBwbG90IGxhc3NvIGZpbmFsIHBlcm11dGF0aW9uLCBmaWcud2lkdGggPSAxMCwgZmlnLmhlaWdodCA9IDEyfQpwbG90X3Blcm11dGVfdmFyX2ltcChmaW5hbF9sYXNzb19wZXJtLCBtZXRyaWMgPSBtZXQpCmBgYAojIyMgQ29tcGFyaXNvbiB3aXRoIGJvb3RzdHJhcCByZXN1bHRzClRoaXMgc2VjdGlvbiBpbnZlc3RpZ2F0ZXMgdGhlIGRpZmZlcmVuY2VzIGluIHRoZSBib290c3RyYXAgcmVzdWx0cyB2cyB0aGUgZmVhdHVyZXMgZ2VuZXJhdGVkIGZyb20gdGhlIExBU1NPIGZpbmFsIG1vZGVsLiAgVGhlIGZvbGxvd2luZyB0YWJsZSBzaG93cyB0aGUgb3ZlcmFsbCBkaWZmZXJlbmNlcyBpbiByYW5rLgoKYGBge3IgY29tcGFyZSBsYXNzbyBmaW5hbCB3aXRoIGJvb3RzdHJhcH0KbGFzc29fam9pbmVkX3Jlc3VsdHMgPC0gZmluYWxfbGFzc29fcGVybSAlPiUKICBkcGx5cjo6c2VsZWN0KC1tZXQpICU+JQogIGZ1bGxfam9pbihkcGx5cjo6c2VsZWN0KGJzX2xhc3NvX3Blcm0sIC1tZXQpLCBieT1jKCJwcmVkaWN0b3IiLCAiYXR0X25hbWUiKSwgc3VmZml4PWMoJy5maW5hbCcsICcuYm9vdHN0cmFwJykpICU+JQogIG11dGF0ZShtZWFuX3JhbmsgPSAob3ZlcmFsbF9yYW5rLmZpbmFsICsgb3ZlcmFsbF9yYW5rLmJvb3RzdHJhcCkvMikgJT4lCiAgYXJyYW5nZShtZWFuX3JhbmspCgpoZWFkKGxhc3NvX2pvaW5lZF9yZXN1bHRzLCAyMCkKYGBgCgpUaGUgZm9sbG93aW5nIHBsb3QgcHJvdmlkZXMgdmlzdWFsaXphdGlvbnMgZm9yIHRoZSBkaWZmZXJlbmNlIGluIHRoZSBmaW5hbCBtb2RlbCByYW5raW5ncyB2cyB0aGUgYm9vdHN0cmFwLgoKYGBge3IgcGxvdCBsYXNzbyBmZWF0dXJlIGNvbXBhcmlzb24sIGZpZy53aWR0aCA9IDE2LCBmaWcuaGVpZ2h0ID0gMTR9CiMgQ29tcGFyaXNvbiBvZiB0b3BfbiBmZWF0dXJlcwpsYXNzb19qb2luZWRfcmVzdWx0cyAlPiUKICBjb21wYXJlX2ZlYXR1cmVfc2VsZWN0KHNlbF9jb2xzID0gYygib3ZlcmFsbF9yYW5rLmZpbmFsIiwgIm92ZXJhbGxfcmFuay5ib290c3RyYXAiKSwKICAgIGludGVyYWN0aXZlID0gVFJVRSwKICAgIHRvcF9uID0gMTAwLAogICAgb3BhY2l0eSA9IDAuNTAsCiAgICBwbG90X3RpdGxlID0gIlBlcm11dGF0aW9uIEltcG9ydGFuY2Ugb2YgUHJlZGljdG9yczogRmluYWwgdnMuIEJvb3RzdHJhcCIpCmBgYAoKIyMgQ29tcGFyaXNvbjogRmluYWwgbW9kZWwgZmVhdHVyZXMKSGVyZSwgd2UgY29tcGFyZSB0aGUgZmVhdHVyZXMgZ2VuZXJhdGVkIGJ5IHRoZSBwZXJtdXRhdGlvbiBpbXBvcnRhbmNlIGJldHdlZW4gdGhlIHR3byBmaW5hbCBtb2RlbHMuCgpgYGB7ciBjb21wYXJlIGxhc3NvIHZzIHJhbmRvbSBmb3Jlc3QgZmVhdHVyZXMgZmluYWx9CnJmX2xhc3NvX2ZpbmFsX2pvaW5lZF9yZXN1bHRzIDwtIGZpbmFsX3JmX3Blcm0gJT4lCiAgZHBseXI6OnNlbGVjdCgtbWV0KSAlPiUKICBmdWxsX2pvaW4oZHBseXI6OnNlbGVjdChmaW5hbF9sYXNzb19wZXJtLCAtbWV0KSwgYnk9YygicHJlZGljdG9yIiwgImF0dF9uYW1lIiksIHN1ZmZpeD1jKCcucmYnLCAnLmxhc3NvJykpICU+JQogIG11dGF0ZShtZWFuX3JhbmsgPSAob3ZlcmFsbF9yYW5rLnJmK292ZXJhbGxfcmFuay5sYXNzbykvMikgJT4lCiAgYXJyYW5nZShtZWFuX3JhbmspCgpoZWFkKHJmX2xhc3NvX2ZpbmFsX2pvaW5lZF9yZXN1bHRzLCAyMCkKYGBgCgpUaGUgZm9sbG93aW5nIHZpc3VhbGl6YXRpb24gcHJvdmlkZXMgdGhlIGludHVpdGlvbiBhYm91dCB0aGUgZGlmZmVyZW5jZXMgaW4gdGhlIHJhbmtpbmdzIGJldHdlZW4gdGhlIGZpbmFsIG1vZGVsIHR5cGVzLiAgVGhleSdyZSBvcmRlcmVkIGJ5IHRoZSBvdmVyYWxsIG1lYW4gaW1wb3J0YW5jZSwgYW5kIGZvciBhIGdpdmVuIHZhcmlhYmxlLCB0aGUgZGlmZmVyZW5jZXMgaW4gcmFuayBhcmUgc2hvd24uCgpgYGB7ciBwbG90bHkgbGFzc28gdiByYW5kb20gZm9yZXN0IGZlYXR1cmVzfQojIENvbXBhcmlzb24gb2YgdG9wX24gZmVhdHVyZXMKcmZfbGFzc29fZmluYWxfam9pbmVkX3Jlc3VsdHMgJT4lCiAgY29tcGFyZV9mZWF0dXJlX3NlbGVjdChzZWxfY29scyA9IGMoIm92ZXJhbGxfcmFuay5yZiIsICJvdmVyYWxsX3JhbmsubGFzc28iKSwKICAgIGludGVyYWN0aXZlID0gVFJVRSwKICAgIHRvcF9uID0gMTAwLAogICAgb3BhY2l0eSA9IDAuNTAsCiAgICBwbG90X3RpdGxlID0gIlBlcm11dGF0aW9uIEltcG9ydGFuY2Ugb2YgUHJlZGljdG9yczogUmFuZG9tIEZvcmVzdCB2cyBMYXNzbyIpCmBgYAoKIyMgQ29tcGFyaXNvbjogRmluYWwgbW9kZWwgcGVyZm9ybWFuY2UKV2l0aCB0aGUgZmluYWwgbW9kZWxzIGdlbmVyYXRlZCwgd2UncmUgbm93IGFibGUgdG8gY29tcGFyZSB0aGVpciBwZXJmb3JtYW5jZSBtZXRyaWNzLgpgYGB7ciBmaW5hbCBtb2RlbCBjb21wYXJpc29uLCBmaWcud2lkdGggPSAxMCwgZmlnLmhlaWdodCA9IDEyfQojIENvbXBhcmlzb24gb2YgcGVyZm9ybWFuY2UgbWV0cmljcwp2YWxpZF9wZXJmIDwtIGdldF9tZXRyaWNfc2V0X2Zyb21fcGVyZnMocGVyZl9saXN0ID0gbGlzdChmaW5hbF9yZl9wZXJmLCBmaW5hbF9sYXNzb19wZXJmKSkgJT4lCiAgbXV0YXRlKG1vZGVsID0gYygncmYnLCAnbGFzc28nKSkKCnRlc3RpbmdfcGVyZiA8LSBnZXRfbWV0cmljX3NldF9mcm9tX21vZGVscyh0ZXN0aW5nX2RmLCBsaXN0KGZpbmFsX21vZGVsX3JmLCBmaW5hbF9tb2RlbF9sYXNzbyksIG91dD1vdXRjb21lKSAlPiUKICBtdXRhdGUobW9kZWwgPSBjKCdyZicsICdsYXNzbycpKQpgYGAKCioqVmFsaWRhdGlvbiBhbmQgc2VsZWN0aW9uLioqClRoZSBmb2xsb3dpbmcgdGFibGUgc2hvd3MgdGhlIGNvbXBhcmlzb24gYmV0d2VlbiBtb2RlbHMgaW4gdGVybXMgb2YgdGhlIHZhbGlkYXRpb24gc2V0LiAgV2UgY2FuIHNlbGVjdCBvdXIgZmluYWwgbW9kZWwgYmFzZWQgb24gdGhlIGJlc3QgcGVyZm9ybWluZyBtb2RlbCBhY2NvcmRpbmcgdG8gdGhlIG1ldHJpYy4KYGBge3J9CnByaW50KHZhbGlkX3BlcmYpCmBgYAoKKipUZXN0aW5nIHBlcmZvcm1hbmNlLioqClRoZSBmb2xsb3dpbmcgc2hvd3MgdGhlIHBlcmZvcm1hbmNlIG9mIGJvdGggdGhlIG1vZGVscyBvbiB0aGUgdGVzdCBzZXQuICBOb3RlIHRoYXQgYWx0aG91Z2ggd2UgZG9uJ3QgdXNlIHRoaXMgdGVzdCBzZXQgdG8gZXZhbHVhdGUgdGhlIGZpbmFsIG1vZGVscywgd2UgY2FuIHN0aWxsIHNlZSBob3cgb3VyIHNlbGVjdGVkIG1ldGhvZCB3b3VsZCBoYXZlIHBlcmZvcm1lZC4KYGBge3J9CnByaW50KHRlc3RpbmdfcGVyZikKYGBgCgpUaGUgZm9sbG93aW5nIHBsb3RzIHNob3cgYSBjb21wYXJpc29uIGJldHdlZW4gdGhlIHBlcmZvcm1hbmNlIG9mIHRoZSBtb2RlbHMgb24gdGhlIHZhbGlkYXRpb24gYW5kIHRlc3Qgc2V0cy4gIEFnYWluLCB3ZSBkb24ndCBjaG9vc2UgdGhlIG1vZGVsIGJhc2VkIG9uIHRoZSB0ZXN0IHNldCwgYnV0IGN1cmlvc2l0eSBkaWN0YXRlcyB0aGF0IHdlIHZpZXcgdGhpcyBwZXJmb3JtYW5jZS4KCmBgYHtyIGZpZy53aWR0aCA9IDEwLCBmaWcuaGVpZ2h0ID0gNn0KIyBTaG93IHBsb3RzIHNpZGUgYnkgc2lkZQptZXRyaWNzX29mX2ludGVyZXN0ID0gYygnbW9kZWwnLCAnYWNjdXJhY3knLCAnYmFsX2FjY3VyYWN5JywgJ21wY2UnLCAnc2VucycsICdzcGVjJywgJ3BwdicsICducHYnLCAncHJfYXVjJywgJ3JvY19hdWMnKQp2YWxpZF9wbHQgPC0gcGxvdF9tZXRyaWNfc2V0KGRwbHlyOjpzZWxlY3QodmFsaWRfcGVyZiwgYWxsX29mKG1ldHJpY3Nfb2ZfaW50ZXJlc3QpKSwgcGxvdF90aXRsZSA9ICJNb2RlbCBjb21wYXJpc29uIGZvciB2YWxpZGF0aW9uIHNldCIpCnRlc3RfcGx0IDwtIHBsb3RfbWV0cmljX3NldChkcGx5cjo6c2VsZWN0KHRlc3RpbmdfcGVyZiwgYWxsX29mKG1ldHJpY3Nfb2ZfaW50ZXJlc3QpKSwgcGxvdF90aXRsZSA9ICJNb2RlbCBjb21wYXJpc29uIGZvciB0ZXN0aW5nIHNldCIpCmdyaWRFeHRyYTo6Z3JpZC5hcnJhbmdlKGdyaWRFeHRyYTo6YXJyYW5nZUdyb2IodmFsaWRfcGx0LCB0ZXN0X3BsdCwgbmNvbD0yLCBucm93PTEpKQpgYGAKCiMgT3RoZXIgY2xlYW51cApgYGB7ciBzaHV0ZG93biBoMm8gaW5zdGFuY2V9Cmgyby5zaHV0ZG93bihGQUxTRSkKYGBgCg==